我试图理解以下代码,特别是StringConstant:
type StringConstant = StringConstant of string * string
[<EntryPoint>]
let main argv =
let x = StringConstant("little", "shack")
printfn "%A" x
0 // return an integer exit code
Run Code Online (Sandbox Code Playgroud)
(通过上下文,StringConstant用于FParsec教程,但此示例不使用FParsec.)
我想知道的是:
类型语句究竟在做什么?
一旦我实例化x,我将如何访问各个"部分"("小"或"房子")
正如其他人已经注意到的那样,从技术上讲,StringConstant
只有一个案例是一个有区别的联合,你可以使用模式匹配来提取价值.
在谈论F#中的域建模时,我喜欢使用另一种有用的类比.通常,您可以通过说某些数据类型是元组来开始:
type Person = string * int
Run Code Online (Sandbox Code Playgroud)
这是表示数据的简单方法,但问题是,当您编写时"Tomas", 42
,编译器不知道您的意思Person
,而是将其理解为string * int
元组.一个案例歧视的工会是一个非常好的方式来命名你的元组:
type Person = Person of string * int
Run Code Online (Sandbox Code Playgroud)
这可能有点令人困惑,因为它使用了Person
两次名称- 首先作为类型名称,然后作为案例名称.这没有特殊意义 - 它只是意味着类型将与案例具有相同的名称.
现在你可以编写Person("Tomas", 42)
创建一个值,它将有一个类型Person
.您可以使用match
或分解它let
,但您也可以轻松编写所需的函数Person
.例如,要返回名称,您可以编写:
let getName (Person(name, _)) =
name
Run Code Online (Sandbox Code Playgroud)
我认为单一案例的歧视联盟经常被使用,主要是因为它们很容易定义并且非常容易使用.但是,我不会在作为公共API公开的代码中使用它们,因为它们有点不寻常并且可能令人困惑.
PS:另请注意,在提取值时需要使用括号:
// Correct. Defines symbols 'name' and 'age'
let (Person(name, age)) = tomas
// Incorrect! Defines a function `Person` that takes a tuple
// (and hides the `Person` case of the discriminated union)
let Person(name, age) = tomas
Run Code Online (Sandbox Code Playgroud)