type Bar = A | B
type Foo = C of Bar | D of Bar
let case = Unchecked.defaultof<Foo>;;
match case with
| C A -> ""
| C B -> ""
| _ -> "Matches";;
match case with
| C A -> ""
| D B -> ""
| _ -> "Throws"
快速浏览F#语言规范,没有关于空测试(我无论如何也不能做)似乎是相关的,两种类型似乎都是引用类型(AFAIK)。
我认为第一种情况下的行为是正确的。
答案 0 :(得分:3)
我认为一旦你使用Unchecked.defaultof<_>
(因此“未经检查”;-)),所有赌注都会被取消。从F#透视图中,Null不被视为类型Foo
的有效值(尽管它来自.NET的角度),因此我不认为模式匹配语义是定义的。
你想做什么?
答案 1 :(得分:3)
所以阅读规范,第一个提示就在这里
b)将null作为异常值的类型。这些类型都可以 不承认null文字,但确实将null作为异常值。
此类别中的类型包括:
o所有F#列表,记录,元组,函数,类和接口类型。
o除了具有null作为正常值的那些之外,所有F#union类型 (如下一段所述)。
对于这些类型,使用null文字不是直接的 允许的。然而,严格地说,它可以生成一个 使用某些函数的这些类型的null值 Unchecked.defaultof。对于这些类型,null被认为是 异常值。关于空值的操作行为 在§6.9中定义。
这似乎表明,在传入一个null值时你的union可能是某种未定义的行为,因为值是“异常”,第6.9节并不是特别有帮助
查看_
的定义,看来你是对的,这是一个错误 - 它说明了
7.1.7通配符模式
模式_是通配符模式并匹配任何输入。对于 例如:
让分类x =
match x with | 1 -> 0 | 0 -> 1 | _ -> 0
我认为最相关的提示稍后会列出DU的编译方法
8.5.3从其他CLI语言使用的联合类型的编译表格
编译的联合类型U将具有:
·每个nullary联合的一个CLI静态getter属性U.C. case C.这将得到一个代表该案例的单例对象。
·每个非nullary union case C的一个CLI嵌套类型U.C 此类型将具有实例属性Item1,Item2 .... union case的字段,或单个实例属性Item,如果有的话 只是一个领域。只有一个案例的编译联合类型不会 有一个嵌套类型。相反,联合类型本身扮演着角色 案件类型。
·每个非Nullary union案例的一个CLI静态方法U.NewC C.这将为该案件构建一个对象。
·每个返回的案例C的一个CLI实例属性u.IsC 对于案件是真是假。
·每个获取的案例C的一个CLI实例属性u.Tag 或者计算与案例相对应的整数标记。
由此可以看出,所有检查方法都是实例方法,这些方法需要非空值。正弦null
是“异常”,生成的代码不会检查,所以它会抛出。
我认为根据_
的定义,你可能会认为这实际上是一个错误。但是,修复它需要在每次DU模式匹配检查之前插入空检查,这会显着降低代码速度,所以我怀疑这是否会被修复
答案 2 :(得分:2)
Unchecked.defaultof方法的描述以句子“此函数在某些F#值没有正确的空值的意义上是不安全的”结束,这就是这里的情况。
试试这个:
let isNull = (case = null) ;;
let isNull = (case = null) ;;
---------------------^^^^
stdin(3,22): error FS0043: The type 'Foo' does not have 'null' as a proper value
>
DU意图是不可变的,没有适当的空值。
答案 3 :(得分:2)
针对具有两种情况的DU的模式匹配编译为具有类型测试的if/else
。如果你翻译你的例子,行为是显而易见的。
match case with
| C A -> ""
| C B -> ""
| _ -> "Matches"
转换为
if (case is C)
...
else
"Matches"
和
match case with
| C A -> ""
| D B -> ""
| _ -> "Throws"
转换为
if (case is D)
...
else //must be C
//check tag BANG! NRE
和kvb的例子:match case with | C _ -> "C" | D _ -> "D"
if (case is D)
//...
else //must be C
"C"
我认为您可以将此视为合理的优化(与if (case is D) {...} else if (case is C) {...} else { MatchFailureException }
相比),因为null
行为未定义。
将第三个案例添加到Foo
,问题就会消失。
答案 4 :(得分:0)
我目前无法确认这一点,但类型的AddNullLiteral属性是否允许匹配成功?