F#记录的奇怪行为 [英] Strange behavior of F# records

查看:105
本文介绍了F#记录的奇怪行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在某些情况下,F#记录的行为对我来说很奇怪:

There is a few cases when F# records behavior is strange to me:

没有歧义警告

type AnotherPerson = {Id: int; Name: string}
type Person = {Id: int; Name: string;}

// F# compiler will use second type without any complains or warnings
let p = {Id = 42; Name = "Foo";}

警告是要对记录进行解构,而不是对记录进行构造

F#编译器未在以前的情况下收到有关记录构造的警告,而是对记录解构"发出了警告:

Instead of getting a warning on records construction in previous case, F# compiler issued a warning on records "deconstruction":

// Using Person and AnotherPerson types and "p" from the previous example!
// We'll get a warning here: "The field labels and expected type of this 
// record expression or pattern do not uniquely determine a corresponding record type"
let {Id = id; Name = name} = p

请注意,模式匹配不会发出警告(我怀疑那是因为模式是使用记录构造表达式"而非记录解构表达式"构建的):

Note, that there is no warnings with pattern matching (I suspect thats because patterns are built using "records construction expressions" and not with "records deconstruction expression"):

match p with
| {Id = _; Name = "Foo"} -> printfn "case 1"
| {Id = 42; Name = _} -> printfn "case 2"
| _ -> printfn "case 3"

缺少字段的类型推断错误

F#编译器将选择第二种类型,然后由于年龄"字段丢失而将发出错误!

F# compiler will choose second type and than will issue an error because Age field is missing!

type AnotherPerson = {Id: int; Name: string}
type Person = {Id: int; Name: string; Age: int}

// Error: "No assignment given for field 'Age' of type 'Person'"
let p = {Id = 42; Name = "Foo";}

记录解构"的丑陋语法

我问了我的几个同事一个问题:这段代码是关于什么的?"

I asked several collegues of mine a question: "What this code is all about?"

type Person = {Id: int; Name: string;}
let p = {Id = 42; Name = "Foo";}

// What will happend here?
let {Id = id; Name = name} = p

这让每个人都感到惊讶,尽管"id"和"name"实际上是左值",尽管它们位于表达式的右手侧".我了解这更多是关于个人喜好,但是对于大多数人来说,奇怪的是,在特定情况下,输出值位于表达式的右侧.

That was total surprise for everyone that "id" and "name" are actually "lvalues" although they placed at the "right hand side" of the the expression. I understand that this is much more about personal preferences, but for most people seems strange that in one particular case output values are placed at the right side of the expression.

我不认为所有这些都是bug,我怀疑其中大部分都是功能.
我的问题是:这种晦涩的行为背后有什么道理吗?

I don't think that all of this are bugs, I suspect that most of this stuff are actually features.
My question is: is there any rational behind such obscure behavior?

推荐答案

您的示例可以分为两类:记录表达式记录模式.记录表达式需要声明所有字段并返回一些表达式,而记录模式具有可选字段,并且用于模式匹配. 记录"的MSDN页面上有两个清晰的部分,也许值得阅读.

Your examples can be divided into two categories: record expressions and record patterns. While record expressions require to declare all fields and return some expressions, record patterns have optional fields and are for the purpose of pattern matching. The MSDN page on Records have two clear sections on them, it may worth a read.

在此示例中,

type AnotherPerson = {Id: int; Name: string}
type Person = {Id: int; Name: string;}

// F# compiler will use second type without any complains or warnings
let p = {Id = 42; Name = "Foo";}

根据上面的MSDN页面中所述的规则,该行为很明显.

最近声明的类型的标签优先于 那些先前声明的类型

The labels of the most recently declared type take precedence over those of the previously declared type

在模式匹配的情况下,您将重点放在创建所需的绑定上.所以你可以写

In the case of pattern matching, you focus on creating some bindings you need. So you can write

type Person = {Id: int; Name: string;}
let {Id = id} = p

以获得id绑定以供以后使用. let绑定上的模式匹配可能看起来有些怪异,但这与您通常在函数参数中进行模式匹配的方式非常相似:

in order to get id binding for later use. Pattern matching on let bindings may look a bit weird, but it's very similar to the way you usually pattern match in function parameters:

type Person = {Id: int; Name: string;}
let extractName {Name = name} = name

我认为关于模式匹配示例的警告是合理的,因为编译器无法猜测您的意图.

I think warnings on your pattern matching examples are justified because the compiler can't guess your intention.

但是,不建议使用具有重复字段的不同记录.至少您应该使用合格的名称来避免混淆:

Nevertheless, different records with duplicate fields are not recommended. At least you should use qualified names to avoid confusion:

type AnotherPerson = {Id: int; Name: string}
type Person = {Id: int; Name: string; Age: int}

let p = {AnotherPerson.Id = 42; Name = "Foo"}

这篇关于F#记录的奇怪行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆