这是否暗示每当我传递一个非可空类型的数组时,我仍然应该检查它是否为空?实际上甚至无法检查<> 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 = ()
答案 0 :(得分:3)
它取决于传递数组的位置。
如果数组是在F#中创建和使用的,那么不,你不需要检查null;实际上,你不应该检查null(使用Unchecked.defaultOf
),因为在某些情况下,F#编译器优化了一些特殊值,如[]
(和None
)通过在编译的IL中将它们表示为null
。
如果您正在使用另一种语言(例如C#)编写的代码来传入数组,那么是的,您仍然应该检查null。如果调用代码只是创建了数组并且没有进一步改变它,那么你只需要执行一次null检查。
编辑:以前是关于F#编译器如何使用null
优化某些值的表示的讨论:Why is None represented as null?
答案 1 :(得分:2)
正如Array.zeroCreate
的文档所示,它会将元素初始化为Unchecked.defaultof<_>
。因此,这带有直接使用Unchecked.defaultof
的所有相同注意事项。一般来说,我的建议是尽可能使用Array.create
/ Array.init
,并将Array.zeroCreate
视为可能的性能优化(在处理非可空类型时需要小心)。
答案 2 :(得分: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()