在F#交互式环境中尝试以下代码时
> let a = None
- let b = (a, Some 1);;
> b;;
val it : 'a option * int option = (null, Some 1)
表明b的类型为'a选项* int选项,b的类型正确。但是,元组的第一个元素的值为null,而不是None,为什么?
当尝试验证元组的第一个元素是否真的为空时
printfn "%s" (match b with (null, _) -> "null" | _ -> "not null");;
出现以下错误
错误FS0043:类型“选项”不包含“空” 值
当尝试获取元组中的fisrt值时,
let c = fst b;;
它给出了
错误FS0030:值限制。值“ c”已推断为 具有通用类型 val c:'_a选项要么将'c'定义为一个简单的数据项,要么使其成为具有显式参数的函数,或者如果您不打算使用它, 要通用,请添加类型注释。
答案 0 :(得分:4)
值None
的内部表示确实是一个null
值。但这是内部表示,编译器将null
和None
标识为两个完全不同的值,因此您无法将它们进行比较,因为它们是不同的类型。这就是为什么您得到:error FS0043
。
这实际上是要注意的事情:
let a = None
let b = (a, Some 1)
let print v = printfn "%A" v
sprintf "%A" a |> print // "<null>"
sprintf "%A" b |> print // "(None, Some 1)"
sprintf "%O" a |> print // "<null>"
sprintf "%O" b |> print // "(, Some(1))"
string a |> print // ""
string b |> print // "(, Some(1))"
a .IsNone |> print // true
a .IsSome |> print // false
a .GetType() |> print // System.NullReferenceException: Object reference not set to an instance of an object.
a .ToString() |> print // System.NullReferenceException: Object reference not set to an instance of an object.
(fst b).ToString() |> print // System.NullReferenceException: Object reference not set to an instance of an object.
(snd b).ToString() |> print // "Some(1)"
...,因为在None
值上调用某些方法会引发可怕的NullReference
异常,并且转换为字符串也很不稳定。
关于error FS0030
,基本上值不能通用。 SO中对此进行了多次讨论。
歧视工会的价值观似乎受到特殊对待,似乎被授予例外,例如,这些都是通用的,但仍然可以:
type MyDU<'A, 'B> =
| ValNo
| ValA of 'A
| ValB of 'B
let v1 = ValNo // MyDU<'a,'b> double generic but Ok
let v2 = ValA 1 // MyDU<int,'a> generic but Ok
let v3 = ValB 1 // MyDU<'a,int> generic but Ok
但是这些都不行
let valNo() = ValNo
let valA a = ValA a
let valB b = ValB b
let w1 = valNo() // MyDU<'_a,'_b> double generic not Ok
let w2 = valA 1 // MyDU<int,'_a> generic not Ok
let w3 = valB 1 // MyDU<'_a,int> generic not Ok