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 允許使用者定義特殊形式。