如何解构构造函数参数?

5
在 F# 中,我可以在语法的各个地方使用模式匹配。例如:
// Given this type...
type SingleCaseUnion = | SingleCaseUnion of int

/// ...I can do this:
let destructureInFunc (SingleCaseUnion n) =
    printfn "%d" n

// ...and this:
type DestructureInMethod() =
    member t.M(SingleCaseUnion n) =
        printfn "%d" n

但是我不知道如何做到这一点:
type DestructureInCtor(SingleCaseUnion n) =
    do printfn "%d" n

//  type DestructureInCtor(SingleCaseUnion n) =
//  ---------------------------------------^
//
// stdin(3,40): error FS0010: Unexpected identifier in type definition. Expected ')' or other token.

我语法错了吗?还是F#不支持在构造函数参数中使用模式匹配?

虽然它不能用于主要构造函数,但其他(次要)构造函数允许它。(由于我的答案变得多余,因此重新发布为评论。) - Vandroiy
1个回答

5
不行,语言规范明确表示不行:
primary-constr-args : attributesopt accessopt (simple-pat, ... , simplepat)
simple-pat :
 | ident
 | simple-pat : type

正如已经指出的那样,次要构造函数允许模式匹配参数,但与主构造函数的区别在于主构造函数的每个参数都是一个函数参数和一个私有字段声明。如果F#允许在此进行模式匹配,那么有些模式将会破坏这种一参数一字段的关系。
type DestructureInCtor(SingleCaseUnion _) = 
    // doesn't declare a private field

or:

type DestructureInCtor((a:int, b:int)) = 
    // declares two private fields? 

我觉得这种做法不是不可能成功,但我猜想允许模式匹配扩展到提供字段声明的复杂程度超过了其好处。


查看规范的8.6.1.3节,似乎没有一对一的参数-字段关系。根据它们的使用情况,参数可能会保留在构造函数中,就像主构造函数中的 let 绑定一样。 (请参见规范中“输入 y 仅在构建期间使用”的示例) 鉴于主构造函数的其余部分允许模式匹配,我不明白为什么它们会在参数列表中增加太多复杂性。 - Vandroiy
@Vandroiy 你说得对,如果一个参数没有被用作字段,那么就不会创建任何字段。但是这些参数与常规函数参数是不同的。这就是为什么允许在此处使用模式匹配会增加复杂性,而我建议语言设计师并未将其列入首要任务。 - Tim Rogers
我正在比较 let 绑定和函数参数。为什么 MyType (pattern) = 不直接编译为 MyType (a) = (newline) let pattern = a 呢?乍一看似乎并没有增加太多复杂性。 - Vandroiy
@Vandroiy 参数被编译为成员字段,而不是 let 绑定,并通过 .NET 运行时公开。 - Tim Rogers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接