Var 返回类型

过程、转换器或者迭代器可以返回 var 类型,表示返回的是一个左值,调用者可以修改它:

  1. var g = 0
  2. proc writeAccessToG(): var int =
  3. result = g
  4. writeAccessToG() = 6
  5. assert g == 6

如果隐式创建的指向某地址的指针,有可能在其生命周期之外继续访问它,那么编译器会报告静态错误:

  1. proc writeAccessToG(): var int =
  2. var g = 0
  3. result = g # 错误!

当迭代器返回元组时,元组的元素也可以是 var 类型:

  1. iterator mpairs(a: var seq[string]): tuple[key: int, val: var string] =
  2. for i in 0..a.high:
  3. yield (i, a[i])

在标准库中,所有返回 var 类型的例程,都遵循以 m 为前缀的命名规范。

通过 var T 返回的内存是安全的,这由简单的借用规则来保证: 如果 result 未指向堆的地址(即在 result = X 中, X 涉及到 ptr 或 ref 访问),那么它必须来自例程的第一个参数。

  1. proc forward[T](x: var T): var T =
  2. result = x # 可以, 来自第一个参数。
  3. proc p(param: var int): var int =
  4. var x: int
  5. # 我们知道 'forward' 提供了一个从其第一个参数 'x' 得出的地址的视图
  6. result = forward(x) # 错误: 地址来自 `x` ,
  7. # 其不是p的第一个参数,
  8. # 并且存活在栈上。

换句话说, result 所指向的生命周期与第一个参数的生命周期相关联,这就足以验证调用位置的内存安全。

未来的方向

新版本的 Nim 借用规则将更加准确,比如使用这样的语法:

  1. proc foo(other: Y; container: var X): var T from container

这里的 var T from contaner 显式指定了返回值的地址必须源自第二个参数(本例的 ‘container’)。 var T from p 语句指明了类型 varTy[T, 2] 与 varTy[T, 1] 类型不兼容。