1

这是否意味着每当我传递一个不可为空类型的数组时,我仍然应该检查它是否为空?实际上它甚至不可能检查<> null但必须使用operator.unchecked。它比 C# 更好吗?

type test=
    {
        value: int
    }

let solution = Array.zeroCreate 10

solution.[0] <- {value = 1}
solution.[1].value   // System.NullReferenceException: Object reference not set to an instance of an object

type test =
  {value: int;}
val solution : test [] =
  [|{value = 1;}; null; null; null; null; null; null; null; null; null|]
val it : unit = ()
4

3 回答 3

3

这取决于从哪里传递数组。

如果数组仅在 F# 中创建和使用,则不,您不需要检查 null;实际上,您不应该检查 null (使用Unchecked.defaultOf),因为 F# 编译器通过在编译的 IL 中表示它们来优化一些特殊值,例如[](和None,在某些情况下) 。null

如果您正在使用由用另一种语言(例如 C#)编写的代码传入的数组,那么是的,您仍然应该检查 null。如果调用代码只是创建数组并且没有进一步改变它,那么您只需要执行一次空值检查。

编辑:这是关于 F# 编译器如何使用以下方法优化某些值的表示的先前讨论null为什么 None 表示为 null?

于 2012-12-16T15:13:23.513 回答
2

如文档Array.zeroCreate所示,它将元素初始化为Unchecked.defaultof<_>. 因此,这带有与直接使用相同的所有警告Unchecked.defaultof。一般来说,我的建议是尽可能使用Array.create/ Array.init,并将其 Array.zeroCreate视为可能的性能优化(在处理不可为空的类型时需要小心)。

于 2012-12-17T07:14:09.477 回答
1

您正在创建一个记录类型,它被实现为一个类,它确实可以为空。如果您打算创建一个结构,您的代码应如下所示:

type test =
    struct
        val value: int
        new(v) = { value = v }
        override x.ToString() = x.value.ToString()
    end

let solution = Array.zeroCreate 10

solution.[0] <- test(1)

这输出:val solution : test [] = [|1; 0; 0; 0; 0; 0; 0; 0; 0; 0|]

您还可以使用 Struct 属性编写类型,从而节省一定程度的缩进。

[<Struct>]
type test =
    val value: int
    new(v) = { value = v }
    override x.ToString() = x.value.ToString()
于 2012-12-16T13:47:20.220 回答