文档 / 语言手册 / Let 绑定
Edit

Let 绑定

在其他语言中,“let 绑定”可能被称为“变量声明”。let 将值与名字 绑定,它们可以被后面的代码看到和引用。

ReScriptJS Output
let greeting = "hello!"
let score = 10
let newScore = 10 + score

块作用域

可以通过 {} 限制绑定的作用域。

ReScriptJS Output
let message = {
  let part1 = "hello"
  let part2 = "world"
  part1 ++ " " ++ part2
}
// `part1` and `part2` not accessible here!

作用域最后一行的值被隐式返回。

设计决策

ReScript 的 ifwhile 和函数都使用相同的块作用域机制。下面的代码之所以有效,并不是因为有什么特殊的“if 作用域”;而是因为它与你刚才看到的作用域语法和特性相同。

ReScriptJS Output
if displayGreeting {
  let message = "Enjoying the docs so far?"
  Js.log(message)
}
// `message` not accessible here!

绑定是不可变的

let 绑定是“不可变的”,也就是“不能改变”。这帮助 Rescript 的类型系统进行比其他语言更多的推理和优化(反过来,也能更好地帮助你)。

绑定覆盖

上述限制一开始可能听起来不切实际。那么如何改变一个值呢?通常情况下,有两种方法:

首先是要意识到,很多时候,你想要的并不是改变一个变量的值。例如,这样的 JavaScript 代码:

JS
var result = 0; result = calculate(result); result = calculateSomeMore(result);

这种写法只是对中间步骤进行注释,你完全不需要修改 result!你可以直接这样写:

JS
var result1 = 0; var result2 = calculate(result1); var result3 = calculateSomeMore(result2);

在 ReScript 中这当然也没问题:

ReScriptJS Output
let result1 = 0
let result2 = calculate(result1)
let result3 = calculateSomeMore(result2)

此外,用相同的名字进行 let 绑定会覆盖之前的同名绑定。所以你也可以这样写:

ReScriptJS Output
let result = 0
let result = calculate(result)
let result = calculateSomeMore(result)

(虽然为了清晰起见,我们不推荐这样做)。

事实上,即使这也是有效的代码:

ReScriptJS Output
let result = "hello"
Js.log(result) // prints "hello"
let result = 1
Js.log(result) // prints 1

你引用的绑定是上方距离最近绑定。这里没有修改!如果你需要 真正的 修改,比如说把一个值传来传去,让它被很多段代码修改,我们提供了一个稍微重一点的可变性特性

私有 let 绑定

私有 let 绑定在 7.2 版本中引入。

在模块系统中,所有东西默认是公开的,隐藏某些值的唯一方式是提供一个独立的模块签名,列出模块中的公共字段和他们的类型:

RES
module A: { let b: int } = { let a = 3 let b = 4 }

使用 %%private 可以直接标记私有字段

RES
module A = { %%private(let a = 3) let b = 4 }

%%private 也可用于文件级模块,所以在某些情况下,用户不需要为了隐藏某些特定的值而提供一个单独的接口文件。

注意,仍然建议将接口文件作为通用最佳实践,因为接口给你提供了更好的独立编译单元,而且对文档更友好。

不过,%%private 在以下场景还是很有用的:

  • 代码生成器。一些代码生成器想要隐藏某些值,但对于代码生成器来说,为公共字段合成类型有时非常困难或耗费时间

  • 快速原型设计。在原型设计过程中,我们仍然希望隐藏一些值,但接口文件还不稳定,%%private 为你提供了这种便利