Sway 参考手册/赋值
一旦变量被声明,就可以使用赋值运算符改变它的绑定。考虑以下与解释器的交互
sway> var BLACK = 1; //initialization! INTEGER: 1 sway> var BROWN = 2; INTEGER: 2 sway> var GREEN = 3; INTEGER: 3 sway> var eyeColor = BLACK; INTEGER: 1 sway> eyeColor; INTEGER: 1 sway> eyeColor = GREEN; //assignment! INTEGER: 3 sway> eyeColor == BROWN; //equality? SYMBOL: :false sway> eyeColor == GREEN; SYMBOL: :true
运算符/变量 = (等于号)绑定到赋值函数。然而,赋值函数不是一个真正的函数,不像那些绑定到 + 和 * 的函数。回想一下,+ 之类的东西会在将它们组合起来之前评估两边的内容(回想一下,两边的内容在一般情况下被称为操作数)。对于 =,左操作数不会被评估(如果被评估了,赋值
eyeColor = GREEN
会尝试将 1 的含义更改为 3)。一般来说,一个不评估所有参数的运算符被称为特殊形式[1].
现在我们可以看到变量定义有两个步骤。在第一步中,变量被创建,在第二步中,一个值被分配给该变量。
前面交互中给解释器的最后两个表达式指的是 == (相等)运算符。运算符 == 如果它的操作数指的是同一件事则返回 true,否则返回 false。在上面的交互中,变量 BLACK、GREEN 和 BROWN 不应该改变它们最初的值。我们通过使用(主要)大写字母来命名变量来表示那些不应该改变值的变量(这个约定借鉴了早期的编程语言)。使用大写字母强调了(不太)变量的常量性质。
在上面的与解释器的交互中,我们使用整数 1、2 和 3 来表示黑色、棕色和绿色。通过抽象化 1、2 和 3,并赋予它们有意义的名称(即 BLACK、BROWN 和 GREEN),我们发现很容易阅读分配和测试眼睛颜色的代码。我们这样做是因为很难记住哪个整数分配给哪个颜色。如果没有变量 BLACK、BROWN 和 GREEN,我们必须在某处记下一些小笔记来提醒自己是什么是什么。以下是与解释器交互的等效版本,不使用变量 BLACK、GREEN 和 BROWN。
sway> var eyeColor = 1; INTEGER: 1 sway> eyeColor; INTEGER: 1 sway> eyeColor = 3; INTEGER: 3 sway> eyeColor == 2; SYMBOL: :false sway> eyeColor == 3; SYMBOL: :true
在这个交互中,test eyeColor == 3 的意义并不那么明显。
另一种常量方法是使用符号。由于 Sway 有符号作为基元,我们可以完全抛弃类似常量的变量和整数
sway> var eyeColor = :black; SYMBOL: :black sway> eyeColor; SYMBOL: :black sway> eyeColor = :green; SYMBOL: :green sway> eyeColor == :brown; SYMBOL: :false sway> eyeColor == :green; SYMBOL: :true
sway> println("eye color is ",eyeColor); eye color is green SYMBOL: :green
注意这个交互版本的可读性提高了多少。还要注意,符号在打印时没有冒号。
赋值的优先级和结合性
[edit | edit source]赋值在二元运算符中优先级最低。它也是右结合的。右结合允许像这样的语句
a = b = c = d = 0;
它方便地将零同时分配给四个变量,并且等同于
(a = (b = (c = (d = 0))));
因为运算符的右结合性质。由于赋值运算的结果值是赋值的值,所以这个语句按预期工作。
工作原理
[edit | edit source]Sway 对赋值采用了新颖的方法。每次检索一个值时,它的地址都会(通常)保存在内部寄存器中。赋值运算符利用这一事实,通过
- 查找左侧的值
- 检查内部寄存器中是否有有效地址
- 将右侧的值写入有效地址
例如,赋值
x = 3;
通过查找x的值来执行。x的当前值被忽略,但内部寄存器现在包含了x的位置。然后将 3 的值复制到地址,x就有了新的值。
通过这种方法,可以写入数组和列表元素以及对象
a[y] = z; head(tail(items)) = :green; a . f() . b = "hello";
赋值有一些限制。例如,不能使用赋值运算符改变列表的尾部。例如,这种尝试将会失败
tail(items) = list(a,b,c);
因为列表的尾部在 Sway 中没有正常的地址。要改变列表的尾部,可以使用tail=运算符,而不是
items tail= list(a,b,c);
或者
tail=(items,list(a,b,c));
如果你喜欢函数调用语法。
有一个head=运算符用于改变列表的头部,但它绑定到普通的赋值运算符,所以你可以使用两者中的任何一个。
赋值给Thunk
[edit | edit source]如果 thunk 中的代码有常规的 Sway 地址,可以使用赋值运算符来更新该地址的值。这就是forEach函数的工作方式
function forEach($target,items,$body) { while (items != null) { $target = head(items); force($body); items = tail(items); } }
在这里,thunk $target 被重复地用列表的(新)头部更新。一旦使用赋值运算符进行了更新,forEach 的主体就会被强制执行,并重复该过程。forEach 函数可以使用简单的变量调用,例如
var i; forEach(i,range(0,4)) { println("i is ",i); }
或者使用数组或列表位置调用,例如
var i = array(1,2,3); forEach(i[2],range(0,4)) { println("i[2] is ",i[2]); }
或者使用对象成员调用,例如
function bundle(a,b) { this; } var i = bundle(1,2); forEach(i . a,range(0,4)) { println("i . a is ",i . a); }
脚注
[edit | edit source]- ↑ 与大多数语言不同,Sway 允许用户定义特殊形式。