Unchecked.defaultof列表

Jiz*_*ugu 24 f#

考虑:

> Unchecked.defaultof<list<int>>;;
val it : int list = null
> 2 :: 1 :: Unchecked.defaultof<list<int>>;;
val it : int list = [2]
Run Code Online (Sandbox Code Playgroud)

这种行为背后的原因是什么?我希望最终列表为[2; 1]或引发异常.

Tom*_*cek 28

这是非常了不起的问题.我看了F#列表是如何编译的,它解释了行为.我不认为这是错误(这就是为什么defaultofUnchecked模块中,它可能会烧毁你的计算机!)

首先,空列表[]没有null在F#2.0中表示,因为那时你将无法在空列表上调用方法 - 这会破坏很多东西(比如将空列表传递给任何Seq函数).顺便说一句,该None表示为null提高效率,这意味着option<'a>无法实现的seq<'a>,即使它将使Sense界面.

因此,F#使用特殊值list.Empty来表示空列表.现在,此值是与表示非空列表(类型为FSharpList<'T>)的值相同类型的实例.唯一的区别是实例的两个headtail字段都是null.

现在,您可以看到它的发展方向 - 空列表实际上是编译到this.tail字段所在的对象null(并且this.head字段也是null如此,但这并不重要).

list.Tail当字段属性将抛出一个异常this.tailnull(因为这意味着你得到一个空列表的尾部-这是一个错误),但也有一个内部属性list.TailOrNull,其返回值,而不检查并用来编译模式匹配.

例如,这是一个简单的iter函数:

let rec iter (xs:int list) = 
  match list with
  | x::xs -> Console.WriteLine(x); iter xs
  | [] -> ()
Run Code Online (Sandbox Code Playgroud)

这被编译为以下C#代码:

if (list.TailOrNull != null) {
  Console.WriteLine(list.HeadOrDefault);
  iter(list.TailOrNull);
}
Run Code Online (Sandbox Code Playgroud)

这将检查是否list是通过检查其是否空列表list.TailOrNullnull.如果是,则它知道当前list值是list.Empty表示空列表的值(并且它不打印它,HeadOrDefault因为它假定它也是null如此).

如果您使用defaultof创建null明确的值,那么42::null给你的对象,其中TailOrNullnull不过HeadOrDefault42.这就是为什么价值不打印的原因.

TL; DR - 不要Unchecked.defaultof与F#类型一起使用.你永远不知道会发生什么.

  • 但是所有零创建函数呢? (2认同)