gpt4 book ai didi

f# - F# 记录的奇怪行为

转载 作者:行者123 更新时间:2023-12-04 06:20:51 26 4
gpt4 key购买 nike

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

没有关于歧义的警告

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# 编译器在记录“解构”时发出警告,而不是在前一种情况下收到有关记录构造的警告:
// 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

请注意,模式匹配没有警告(我怀疑这是因为模式是使用“记录构造表达式”而不是“记录解构表达式”构建的):
match p with
| {Id = _; Name = "Foo"} -> printfn "case 1"
| {Id = 42; Name = _} -> printfn "case 2"
| _ -> printfn "case 3"

缺少字段的类型推断错误

F# 编译器将选择第二种类型,然后会因为缺少 Age 字段而发出错误!
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";}

“记录解构”的丑陋语法

我问了我的几位同事一个问题:“这段代码是关于什么的?”
type Person = {Id: int; Name: string;}
let p = {Id = 42; Name = "Foo";}

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

尽管“id”和“name”实际上是“左值”,但它们位于表达式的“右手边”,这让每个人都感到惊讶。我知道这更多地与个人喜好有关,但对于大多数人来说,在一种特定情况下输出值放在表达式的右侧似乎很奇怪。

我不认为所有这些都是错误,我怀疑大多数这些东西实际上是功能。
我的问题是: 这种晦涩难懂的行为背后有什么道理吗?

最佳答案

你的例子可以分为两类:记录表达式记录模式 .虽然记录表达式需要声明所有字段并返回一些表达式,但记录模式具有可选字段并且用于模式匹配。 The MSDN page on Records有两个明确的部分,可能值得一读。

在这个例子中,

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";}

the MSDN page above 中所述的规则可以清楚地看出这种行为。 .

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



在模式匹配的情况下,您专注于创建一些您需要的绑定(bind)。所以你可以写
type Person = {Id: int; Name: string;}
let {Id = id} = p

为了得到 id绑定(bind)以备后用。 let 绑定(bind)上的模式匹配可能看起来有点奇怪,但它与您通常在函数参数中进行模式匹配的方式非常相似:
type Person = {Id: int; Name: string;}
let extractName {Name = name} = name

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

但是,不建议使用具有重复字段的不同记录。至少您应该使用限定名称以避免混淆:
type AnotherPerson = {Id: int; Name: string}
type Person = {Id: int; Name: string; Age: int}

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

关于f# - F# 记录的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16016087/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com