从这里:
最近声明的类型的标签优先于先前声明的类型的标签
所以如果你这样做:
type myrec2 = {x: int; y: int; z: int}
type myrec1 = {x: int; y: int}
let p1 = {x = 1; y = 1}
那么它将起作用。
为了您的阅读乐趣(F# 3.0 规范):
field-initializer : long-ident = expr
6.3.5 记录表达式
在这种情况下,我们的字段初始化器不是单个标识符,因此它使用 14.1.9 中的“字段标签解析”。
每个 field-initializeri 的格式为 field-labeli = expri。每个字段标签都是一个长标识,它必须解析为唯一记录类型 R 中的字段 Fi,如下所示:
· 如果 field-labeli 是单个标识符 fld 并且已知初始类型是记录类型 R< ,..., > 具有名称为 fld 的字段 Fi,则字段标签解析为 Fi。
· 如果 field-labeli 不是单个标识符或者如果初始类型是变量类型,则通过对 field-labeli 执行字段标签解析(参见第 14.1 节)来解析字段标签。此过程产生一组字段 FSeti。该集合的每个元素都有一个对应的记录类型,从而产生一组记录类型 RSeti。所有 RSeti 的交集必须产生单个记录类型 R,然后每个字段解析为 R 中的相应字段。
14.1.9 字段标签解析
我们的 long-ident 是一个 FieldLabel,所以它是使用 8.4.2 中描述的 FieldLabels 表查找的。
字段标签解析指定如何解析 { field1 = expr; 中的 field1 等标识符 ...字段N = expr }。字段标签解析通过以下步骤进行:
1. 在 Types 表和 FieldLabels 表(第 8.4.2 节)中查找所有可用类型中的所有字段。
2. 返回字段声明集。
8.4.2 名称解析和记录字段标签
如此处所述,FieldLabels 表用于成员名称解析 (14.1)。
对于记录类型,除非记录类型具有 RequireQualifiedAccess 属性,否则记录字段标签 field1 ... fieldN 将添加到当前名称解析环境的 FieldLabels 表中。FieldLabels 表中的记录字段标签在成员名称解析(第 14.1 节)中发挥特殊作用:可以从记录标签中推断出表达式的类型。例如:类型 R = { dx : int; dy: int } let fx = x.dx // x 被推断为类型 R 在本例中,查找 .dx 被解析为字段查找。
14.1.4 表达式中
的名称解析 这部分看起来有点模糊,但我认为它在这一点上使用了名称解析。如最后所述,如果有多个,则返回第一个项目。
给定输入 long-ident、环境 env 和后续类型参数 < ,..., > 数量的可选计数 n,表达式中的名称解析计算包含 long-ident< ,..的解释的结果。 ., > 作为值或其他表达式项的前缀,以及残差路径。表达式中的名称解析如何进行取决于 long-ident 是单个标识符还是由多个标识符组成。如果 long-ident 是单个标识符 ident:
1. 在 ExprItems 表中查找 ident。返回结果并清空其余部分。
2. 如果 ident 没有出现在 ExprItems 表中,则在 Types 表中查找它,如果可用,则使用与 n 匹配的通用 arity。返回此类型并清空其余部分。
3. 如果 ident 没有出现在 ExprItems 表或 Types 表中,则失败。
...
如果表达式包含歧义,表达式中的名称解析将返回该过程生成的第一个结果。
您感兴趣的部分是上面的最后一行:“返回过程生成的第一个结果”。