F#:为什么选项类型与可空类型不兼容?

Jon*_*len 11 null f#

为什么像"int option"这样的选项类型不兼容像Nullable这样的可空类型?

我假设存在差异的一些语义原因,但我无法弄清楚那是什么.

当值可能存在或不存在时,使用F#中的选项.选项具有基础类型,可以包含该类型的值,也可以没有值.

http://msdn.microsoft.com/en-us/library/dd233245%28VS.100%29.aspx

这肯定听起来像Nullable结构.

t0y*_*yv0 17

由于运行时表示选择System.Nullable<'T>.

Nullable尝试通过空指针表示缺少值,并通过指向这些值的指针来显示值.

(new System.Nullable<int>() :> obj) = null
|> printfn "%b" // true

(new System.Nullable<int>(1) :> obj).GetType().Name
|> printfn "%s" // Int32
Run Code Online (Sandbox Code Playgroud)

现在考虑字符串.不幸的是,字符串可以为空.所以这是有效的:

null : string
Run Code Online (Sandbox Code Playgroud)

但是现在null运行时值是不明确的 - 它可以指缺少值或存在null值.出于这个原因,.NET不允许构造一个System.Nullable<string>.

与此对比:

(Some (null : string) :> obj).GetType().Name
|> printfn "%s" // Option`1
Run Code Online (Sandbox Code Playgroud)

话虽这么说,人们可以定义一个双射:

let optionOfNullable (a : System.Nullable<'T>) = 
    if a.HasValue then
        Some a.Value
    else
        None

let nullableOfOption = function
    | None -> new System.Nullable<_>()
    | Some x -> new System.Nullable<_>(x)
Run Code Online (Sandbox Code Playgroud)

如果观察类型,则这些函数约束'T为结构并具有零参数构造函数.因此,也许F#编译器可以Nullable<'T>通过替换它来接收/返回.NET函数Option<'T where 'T : struct and 'T : (new : unit -> 'T)>,并在必要时插入转换函数.

  • 这不是真的.`Nullable <T>`是一个结构,因此,它的空值不能用空指针表示.相反,C#编译器的特殊情况是`Nullable <T>`类型,允许你使用null文字; 这当然与允许变量保存空指针不一样.可空的struct有一个"has value"布尔字段; C#编译器将与null文字的比较转换为对HasValue属性的调用.运行时还特别处理*boxing*操作,这就是为什么你的第一个例子按预期工作. (4认同)

Bri*_*ian 6

两者有不同的语义.仅举一例,Nullable是一个幂等数据构造函数,仅适用于值类型,而option是普通泛型类型.所以你不能拥有

Nullable<Nullable<int>>
Run Code Online (Sandbox Code Playgroud)

但你可以有一个

option<option<int>>
Run Code Online (Sandbox Code Playgroud)

一般来说,虽然有一些重叠的场景,但你也可以用一个而不是另一个做.

  • @JonathanAllen令人困惑,你可以有一个`字符串选项`,其值为'Some null`. (5认同)
  • 这种特殊情况对我来说似乎并不可取.为什么您希望选项<'a>的某些实例由Nullable <T>表示而不是其他? (3认同)

Rob*_*ert 1

主要区别在于必须测试选项类型以查看它是否具有值。有关其语义的详细描述,请参阅此问题:How does the option type work in F#

  • 不幸的是你错了。您不需要检查选项类型来查看它们是否有值,您可以直接调用 Option&lt;T&gt;.Value 并希望不会出现异常。如果不使用模式匹配,甚至不会出现编译器警告。 (2认同)
  • 提供一种方便的方法,然后告诉人们不要使用它,这与 .NET API 设计的“成功之坑”理念不符。 (2认同)