Var parameters
在 Nim 中过程或方法有两种参数类型,一种是前面有 var 关键字 的参数,另一种是不带 var 的参数。
例如:
proc divmod(a, b: int; res, remainder: var int) =
res = a div b
remainder = a mod b
var
x, y: int
divmod(8, 5, x, y) # modifies x and y
assert x == 1
assert y == 3
在上面的例子中,a,b是不带 var 的参数,它们在过程中是不允许改变的,而 res, remainder 在过程中是能够改变其值的。 传递给 var 参数的必须是一个 l-value.
l-value 介绍:
一个表达式能指定一个产生一个值或位置的计算。产生位置的表达式就是 l-values。(比如:var x = 5 中的 x 就是一个l-value。 5 就不是)。一个 l-value 能够表示一个位置或者这个位置包含的值,这取决于语境。表达式的值能够被静态确定的被称为常量表达式。它们不是 l-values。let 声明的变量不是 l-values。
var 参数是作为隐式的指针实现的,上面的例子与这个例子是等价的:
proc divmod(a, b: int; res, remainder: ptr int) =
res[] = a div b
remainder[] = a mod b
var
x, y: int
divmod(8, 5, addr(x), addr(y))
assert x == 1
assert y == 3
变量在内存中的存储:
上面的例子可以通过返回一个元组的方式来实现:
proc divmod(a, b: int): tuple[res, remainder: int] =
(a div b, a mod b)
var t = divmod(8, 5)
assert t.res == 1
assert t.remainder == 3
var (x, y) = divmod(8, 5) # tuple unpacking
assert x == 1
assert y == 3
Var return type
一个过程、转换器或者迭代器可能返回一个 var 类型,这意味着 这个返回值是一个 l-value 和能够被调用者改变:
var g = 0
proc WriteAccessToG(): var int =
result = g
WriteAccessToG() = 6
assert g == 6
要注意赋给 result 的值得是一个 l-value .
import strutils
discard """
proc WriteAccessToG(): var int =
var g = 0
result = g # Error! Error: address of 'g' may not escape its stack frame
"""
discard """
proc WriteAccessToG(g:int): var int =
result = g # Error! Error: expression has no address
"""
proc WriteAccessToG(g:var int): var int =
result = g
proc WriteAccessToG2(g:ptr int): var int =
result = g[]
proc WriteAccessToG3(g:ptr string): var string = #带var 和不带是不一样的。 带var 是隐式的指针操作, result 与 g 指向同一位置。
echo "repr g = ",repr(g) #不带 var, result 在栈中重新分配一个空间。
#echo "repr result = ",repr(result)
result = g[]
echo "repr result = ",repr(result)
g[0] = 'a'
var
var1 = 5
var2 = "yrs"
echo WriteAccessToG(var1)
echo WriteAccessToG2(addr(var1))
echo "addr(var2) = ",BiggestInt(cast[int](addr(var2))).toHex(12)
echo "repr var2 = ",repr(var2)
echo "returned = ", repr(WriteAccessToG3(addr(var2)))
echo "repr var2 = ",repr(var2)
对于迭代器,一个元组的一部分返回类型可以有一个var 类型:
iterator mpairs(a: var seq[string]): tuple[key: int, val: var string] =
for i in 0..a.high:
yield (i, a[i])
var
x:seq[string]
x = @["a","b","c"]
for m in mpairs(x):
echo m
在标准库里每一个返回一个 var 类型的程序的名子都是以 m 作为前缀。