Null,Undefined & Option
ReScript 本身没有 null
和 undefined
。这实在是件 好事,因为它消除了一整类的 bug。再也不会有 undefined is not a function
和 cannot access someAttribute of undefined
了!
不过,“可能不存在值”这一概念仍然是有用的,并且安全地存在于我们的语言中。
我们将值用 option
类型包装,来表示值的存在与不存在。下面是它在标准库中的定义:
它的意思是“option 类型的值要么是 None(什么也没有),要么是被 Some 包装的那个实际值”。
注意 option
类型只是一个普通的变体。
示例
这是一个普通的值:
为了表示“可能为空”的概念,你可以通过包装把它变成一个 option
类型。为了更好地说明问题,我们给它加上条件表达式:
稍后,当另一段代码收到这样的值时,它会被强制通过模式匹配来处理两种情况:
通过把普通数字变成 option
类型并强迫你处理 None
的情况,ReScript 有效地消除了误处理或者忘记处理(概念上的)null
值的可能性!纯 ReScript 程序不会出现 null 错误。
与 JavaScript 的 undefined
和 null
互操作
option
类型很常见,所以我们在编译成 JavaScript 时会对其进行特殊处理:
会简洁地编译为5
,而
会编译为 undefined
!如果你在 JavaScript 中有一个字符串,你知道它可能是 undefined
,那么把它标注为 option<string>
就完事了!同样地,你可以向 JS 端发送一个 Some(5)
或 None
,并期望它被正确解释 =)。
警告 1
option
到 undefined
的翻译并不是完美的,因为在 ReScript 这边, option
值是可组合的:
这仍然会编译为 5
,但是下面的代码就不太说的清了:
这个 Caml_option.some
是什么东西?为什么它不能直接编译成 undefined
?长话短说,在处理多态 option
类型时(也就是 option<'a>
,'a
为任意类型),如果我们不对值进行一些特殊的标注,许多操作就会变得很棘手。如果这段说明对你没什么意义,别担心,记住下面的规则就行:
永远不要传递一个嵌套的
option
值(比如Some(Some(Some(5)))
)到 JS 端永远不要将一个来自于 JS 的值标注为
option<'a>
类型。总是使用具体的非多态类型
警告 2
不幸的是,很多时候你的 JavaScript 值既可能是 null
也可能是 undefined
。在这种情况下,你不能把这样的值当作 option<int>
类型,因为我们的 option
类型在处理 None
时只检查 undefined
而不检查 null
。
解决方法:更复杂的 undefined
和 null
互操作
为了解决这个问题,我们通过 Js.Nullable
模块提供了更复杂的 null
和 undefined
辅助函数。这有点像 option
类型,但又与之不同。
示例
要创建 JS 的 null
,使用 Js.Nullable.null
的值。要创建 JS 的 undefined
,使用 Js.Nullable.undefined
(你也可以使用 None
,但这不是这里的重点;Js.Nullable.*
里的辅助函数不会对它起作用)。
例如,如果你收到的是一个可以为 null
和 undefined
的 JS 字符串,那就这样声明类型:
如果要从 ReScript 这边创建一个可空(nullable)字符串(假设是为了互操作目的,会把它传递给 JS 端),可以这么做:
return
部分将一个字符串“包装”成一个可空字符串,以使类型系统理解并跟踪这样一个事实:当你传递这个值时,它不仅仅是一个字符串,而是一个可以是 null
或 undefined
的字符串。
与 option
值互相转换
Js.Nullable.fromOption
将一个 option
转换到 Js.Nullable.t
。
Js.Nullable.toOption
做相反的转换。