为什么像“int option”这样的选项类型不兼容像Nullable这样的可空类型?
我认为差异有一些语义上的原因,但我无法弄清楚那是什么。
当值可能存在或不存在时,使用F#中的选项。选项具有基础类型,可以保留该类型的值,也可以没有值。
http://msdn.microsoft.com/en-us/library/dd233245%28VS.100%29.aspx
这肯定听起来像Nullable结构。
答案 0 :(得分:16)
由于System.Nullable<'T>
的运行时表示选择。
Nullable尝试通过空指针表示缺少值,并通过指向这些值的指针显示值。
(new System.Nullable<int>() :> obj) = null
|> printfn "%b" // true
(new System.Nullable<int>(1) :> obj).GetType().Name
|> printfn "%s" // Int32
现在考虑字符串。不幸的是,字符串可以为空。所以这是有效的:
null : string
但现在null
运行时值不明确 - 它可以指缺少值或存在null
值。因此,.NET不允许构造System.Nullable<string>
。
与此对比:
(Some (null : string) :> obj).GetType().Name
|> printfn "%s" // Option`1
即说,可以定义一个双射:
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)
如果观察类型,这些函数将'T
约束为结构并具有零参数构造函数。所以也许F#编译器可以通过替换Nullable<'T>
来公开接收/返回Option<'T where 'T : struct and 'T : (new : unit -> 'T)>
的.NET函数,并在必要时插入转换函数。
答案 1 :(得分:6)
两者有不同的语义。仅举一例,Nullable是一个幂等数据构造函数,仅适用于值类型,而option是普通泛型类型。所以你不能拥有
Nullable<Nullable<int>>
但你可以有一个
option<option<int>>
一般来说,虽然有一些重叠的场景,但也有一些你可以用一个而不是另一个做。
答案 2 :(得分:1)
关键区别在于必须测试选项类型以查看它是否具有值。有关其语义的详细说明,请参阅此问题:How does the option type work in F#
答案 3 :(得分:0)
同样,这是我有限的理解,但问题可能在于每个如何在IL中呈现。 “可空”结构可能与选项类型略有不同。
你会发现各种.Net语言之间的相互作用实际上归结为IL的呈现方式。大部分时间它工作得很好,但偶尔会导致问题。 (check out this)。就在你认为相信抽象层次是安全的时候。 :)