F# 的条件表达式需要一个条件来检查、一个 true 分支和一个 false 分支。例如:
let x =
if ("hello" = null)
then true
else false //error if else branch missing
但是,当涉及
unit
(又名 ()
)时,事情会变得很奇怪。
let y =
if ("hello" = null)
then raise <| new ArgumentNullException()
else () //happy with or without else branch
更简单地说:
let z =
if ("hello" = null)
then ()
else () //happy with or without else branch
为什么返回
else
时不需要 unit
分支?
考虑以下代码:
let f a = if a > 5 then true
如果您调用
f 10
,它会返回 true
。
现在,问自己:
f 2
应该返回什么?我知道你会说false
,但是编译器怎么知道这一点呢?我的意思是,在这两种情况下,您都可能想让它返回 true
,不是吗?或者甚至可能在 a <= 5
的情况下崩溃,谁知道呢?
因此,为了使程序“完整”(即包含在每种情况下执行操作的说明),您始终必须指定一个
else
分支。
unit
是特别。
返回
unit
表示没有任何有意义的返回值。本质上,unit
代表副作用:这意味着返回它的东西意味着对外部世界产生一些影响。由于 F# 不是一种纯粹的语言,因此这种 unit
返回的东西相当普遍。例如,调试日志记录:
let f x =
if x < 42 then printfn "Something fishy, x = %d" x
x + 5
有了这样的陈述,就没有歧义了:众所周知,
else
分支也意味着返回()
。毕竟,unit
没有其他值,不是吗?同时,总是在末尾添加else ()
会非常烦人且令人困惑。因此,为了可用性,编译器在这种特定情况下不需要 else
分支。
在 F# 中,
if
是一个表达式,而不是一个语句。每个表达式都需要返回一个值。并且 if
和 else
都需要返回相同类型的值,因为 F# 是强类型语言。因此,如果没有 else
分支,那么默认情况下它的类型为 unit
,但是如果您的 if
返回的值不是 unit
类型,那么您需要有一个具有相同类型的 else
。
每个分支中生成的值的类型必须匹配。如果没有显式的 else 分支,则其类型为 unit。因此,如果then分支的类型是unit以外的任何类型,则必须有一个具有相同返回类型的else分支。
如果从第一个片段中删除
else
,则相当于
let x =
if ("hello" = null)
then true
else ()
不进行类型检查。
为什么?我猜测是为了与 OCaml 兼容。
部分可以省略,在这种情况下它默认为else expr3
。 (7.7.2)else ()
您可以将
unit
-返回 if
视为与 C 语言 if
语句 等价,而不是表达式。
问题已经回答了,所以我只是用我自己的肤浅观察来跟进
在 F# 中,我们没有语句和表达式。在 F# 中,我们仅使用表达式来进行计算。这是一件好事。
在 C# 中,
if
是一个有意义的语句
if(x)
{
return 1;
}
如果
x
为 true,则停止执行,并将结果返回给调用者:1
。
在 F# 中,其中
if
是一个表达式,这意味着无论采用哪个分支,if
都应该产生一个值。因此这没有什么意义
if x then 1 // What value should else branch evaluate to?
我们必须指定两个分支
if x then 1 else 0
正如其他答案所示,有一种特殊情况,即省略
else
。 if
表达式将产生一个 unit
值,这是我们在 F# 中得到的最接近语句的值。
因为 if
表达式的类型是 unit,所以“true”分支必须是 unit
类型。
if x then () // This works
if x then () else () // This works
if x then 1 // This won't work, type mismatch