1

有人可以解释以下内容,这似乎有点不一致。

这行代码无效:

let l = [("Hi", 1); ("Ho", "One")]

因为元组是不同的 string*int vs string*string OK。

这行代码也是无效的:

let (m: (string*obj) list) = [("Hi", 1); ("Ho", "One")]

我明确告诉它这是一个 string*obj 元组列表,但它不会自动将 1 和 "One" 转换为 obj。也可以。

这行代码是有效的:

let (n: (string*obj) list) = [("Hi", unbox(1)); ("Ho", unbox("One"))]

在这种情况下,我明确地将 1 和“一”拆箱,它可以工作。

这就是我认为事情变得有点不一致的地方。采取以下措施:

type thing =
    {
        name: string
        value: obj
    }

let (p: thing list) = [{name="Hi"; value=1}; {name="Ho"; value="One"}]

该代码有效。值 1 和 "One" 都分配给作为 obj 的 'value'。

为什么我不需要为一个类型的成员拆箱,而是为一个元组中的一个项目拆箱?

4

1 回答 1

3

正如评论中提到的,这有点不一致,但在这种情况下它实际上是有道理的。

要点是编译器永远不会在表达式的子表达式内的任何地方插入装箱。它只会立即执行此操作 - 当调用方法或函数(采用obj)或将值分配给记录字段时。但是,它永远不会(*)在某个更大的表达式中需要它时插入装箱。

因此,在您的示例中,当编译器看到("Hi", 1)and时("Ho", "One"),它只会创建两个类型为string * intand的元组string * string- 然后它会失败,因为它们不匹配。

当编译器看到{name="Hi"; value=1}时,它会发现您正在创建 a thing,因此它会obj自动将 value 参数装箱(然后您最终会得到一个有效的事物列表)。


(*) 唯一的例外是当您创建一个数组或值列表时,但这是编译器中的一个临时特例(这恰好非常有用,但并没有真正帮助您,因为您需要不仅在列表内添加装箱,而且在列表内的元组内添加装箱)。这是有效的:

let (arr:obj list) = [ 1; "hi" ]
于 2013-10-31T17:07:56.790 回答