是否存在编译器实现的原因,为什么记录不能具有AllowNullLiteralAttribute属性或者这是一个选定的约束?
我确实看到这种约束强制清除代码有时但不总是。
[<AllowNullLiteralAttribute>]
type IBTreeNode = {
mutable left : IBTreeNode; mutable right : IBTreeNode; mutable value : int}
with
member this.Insert x =
if x < this.value then
if this.left = null then
this.left <- {left = null; right = null; value = x}
else
this.left.Insert x
else
if this.right = null then
this.right <- {left = null; right = null; value = x}
else
this.right.Insert x
// Would be a lot of boilerplate if I wanted these public
[<AllowNullLiteralAttribute>]
type CBTreeNode(value) =
let mutable left = null
let mutable right = null
let mutable value = value
with
member this.Insert x =
if x < value then
if left = null then
left <- CBTreeNode(x)
else
left.Insert x
else
if right = null then
right <- CBTreeNode(x)
else
right.Insert x
为可变性人群添加了一个不可变版本。在这种情况下,它快了大约30%。
type OBTree =
| Node of OBTree * OBTree * int
| Null
with
member this.Insert x =
match this with
| Node(left, right, value) when x <= value -> Node(left.Insert x, right, value)
| Node(left, right, value) -> Node(left, right.Insert x, value)
| Null -> Node(Null, Null, x)
答案 0 :(得分:3)
我只能冒险猜测,但语言似乎采取的态度是null
的使用是可以避免的(如果你需要这个功能,你总是可以使用option
类型)因此null
的使用实际上应该限于与其他.NET语言互操作。因此,F#特定类型不允许使用null
。
答案 1 :(得分:2)
嗯,记录被翻译成标准的.NET类,就像其他结构一样,所以我没有看到技术原因。
我猜这个决定是相当哲学的 - Null
值是未初始化的,未定义的值,在有状态计算中被取代的东西。在F#等功能上下文中应避免这些。
所以我认为记录类型,作为“功能构造”(不是标准的.NET兼容)并不意味着携带这样的无功能数据,但用户需要手动编码(`选项类型等)。
这也可以让您了解您的代码,例如检查所有可能值的模式匹配,而不存在必须处理null
值的潜在危险。
关于你的代码:你真的要求它是必要的吗?
怎么样?data Tree =
| Node of int * Tree * Tree
| Nil