【问题标题】:F#: Why aren't option types compatible with nullable types?F#:为什么选项类型与可空类型不兼容?
【发布时间】:2009-06-03 20:23:21
【问题描述】:

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

我认为这种差异有一些语义上的原因,但我不知道那是什么。

当值可能存在或可能不存在时,使用 F# 中的选项。一个期权有一个基础类型,可能持有该类型的值,也可能没有值。

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

这听起来确实像 Nullable 结构。

【问题讨论】:

    标签: f# null


    【解决方案1】:

    因为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&lt;string&gt;

    对比:

    (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# 编译器可以通过将 Option&lt;'T where 'T : struct and 'T : (new : unit -&gt; 'T)&gt; 替换为 Option&lt;'T where 'T : struct and 'T : (new : unit -&gt; 'T)&gt; 并在必要时插入转换函数来公开接收/返回 Nullable&lt;'T&gt; 的 .NET 函数。..

    【讨论】:

    • 这不是真的。 Nullable&lt;T&gt; 是一个结构体,因此,它的空值不能用空指针表示。相反,C# 编译器对 Nullable&lt;T&gt; 类型进行特殊处理,允许您使用 null 文字;这当然与允许变量保存空指针不同。可空结构有一个“有值”布尔字段; C# 编译器将与 null 文字的比较转换为对 HasValue 属性的调用。运行时还特别对待 boxing 操作,这就是您的第一个示例按预期工作的原因。
    • 等一下。 Option&lt;T&gt; 表示空指针没有值。如果您查看 Option.None 的定义,它实际上就是 null
    【解决方案2】:

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

    Nullable<Nullable<int>>
    

    但你可以有一个

    option<option<int>>
    

    一般来说,虽然有一些重叠的场景,但也有一些事情你可以用其中一种来做,但不能用另一种来做。

    【讨论】:

    • 这就解释了为什么不能使用 Nullable> 作为 option
    • 这种特殊情况对我来说似乎并不理想。为什么您希望 option 的某些实例由 Nullable 表示而不是其他实例?
    • F# 已经充满了奇怪的特殊情况。例如,接受值或空值的“字符串”与接受值或无值的“字符串选项”有什么区别?
    • @JonathanAllen 令人困惑的是,您可以有一个 string option,其值为 Some null
    【解决方案3】:

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

    【讨论】:

    • 那又怎样?您可以在语言语法级别提出该要求,并在运行时级别仍然使用 Nullable
    • 在运行时级别使用空值表示。
    • 很遗憾你错了。您不需要检查选项类型以查看它们是否具有值,您可以直接调用 Option.Value 并希望您不会遇到异常。如果不使用模式匹配,甚至没有编译器警告。
    • @Jonathan:建议测试选项类型,这就是它的预期使用方式。为方便起见,提供了对值的直接访问,但应避免使用它。
    • 提供方便的方法然后告诉人们不要使用它不符合 .NET API 设计的“成功之坑”哲学。
    【解决方案4】:

    同样,这是我有限的理解,但问题可能在于每个元素如何在 IL 中呈现。 “可空”结构的处理可能与选项类型略有不同。

    您会发现各种 .Net 语言之间的交互实际上归结为 IL 的呈现方式。大多数时候它工作得很好,但有时会引起问题。 (check out this)。就在您认为信任抽象级别是安全的时候。 :)

    【讨论】:

      猜你喜欢
      • 2011-03-31
      • 1970-01-01
      • 1970-01-01
      • 2020-06-17
      • 1970-01-01
      • 1970-01-01
      • 2018-01-24
      • 2022-01-11
      • 1970-01-01
      相关资源
      最近更新 更多