bind
關鍵字將目標變量的值與綁定表達式的值相關聯。綁定表達式可以是某個基本類型的簡單值、對象、函數的結果或表達式的結果。以下幾節分別提供每種綁定表達式
的示例。
在大多數實際的編程情況下,需要通過數據綁定使應用程序的圖形用戶界面 (Graphical User
Interface, GUI) 與其底層數據同步。(GUI 編程是使用 JavaFX 構建
GUI 應用程序的主題;下面我們將用一些非可視的示例來說明基本的底層結構。)
讓我們先看一個簡單的示例:下面的腳本將變量 x
綁定到變量 y
,
更改 x
的值,然后輸出 y
的值。由于這兩個變量綁定在一起,因此 y
值會自動更新為新值。
var x = 0;
def y = bind x;
x = 1;
println(y); // y now equals 1
x = 47;
println(y); // y now equals 47
|
請注意,我們已將變量 y
聲明為 def
。這可防止任何代碼直接
為該變量賦值(盡管允許該變量的值因綁定 (bind
) 而更改)。在綁定到對象時,此約定仍適用(請回顧使
用對象中介紹的 Address
):
var myStreet = "1 Main Street";
var myCity = "Santa Clara";
var myState = "CA";
var myZip = "95050";
def address = bind Address {
street: myStreet;
city: myCity;
state: myState;
zip: myZip;
};
println("address.street == {address.street}");
myStreet = "100 Maple Street";
println("address.street == {address.street}");
|
如果更改 myStreet
的值,address
對象內部的 street
變量將受到影響:
address.street == 1 Main Street
address.street == 100 Maple Street
|
請注意,更改 myStreet
的值實際上會導致創建一個新的 Address
對象,然后將該對象重新賦給 address
變量。為了跟蹤所做的更改而不創建新的 Address
對象,請改為直接綁定 (bind
) 到該對象的實例變量:
def address = bind Address {
street: bind myStreet;
city: bind myCity;
state: bind myState;
zip: bind myZip;
};
|
如果要顯式綁定到實例變量,還可以省略第一個 bind
(Address
前面的那個):
def address = Address {
street: bind myStreet;
city: bind myCity;
state: bind myState;
zip: bind myZip;
};
|
前面的課程已講授了函數,但是您還必須了解綁定函數與非綁定函數之間的區別。
請考慮下面的函數,該函數創建和返回一個 Point
對象:
var scale = 1.0;
bound function makePoint(xPos : Number, yPos : Number) : Point {
Point {
x: xPos * scale
y: yPos * scale
}
}
class Point {
var x : Number;
var y : Number;
}
|
這就是所謂的綁定函數,因為它前面有 bound
關鍵字。
注意:bound
關鍵字不能替換 bind
關鍵字;這兩個關鍵字按如下所示方式結合使用。
接下來,讓我們添加一些代碼來調用此函數并測試綁定:
var scale = 1.0;
bound function makePoint(xPos : Number, yPos : Number) : Point {
Point {
x: xPos * scale
y: yPos * scale
}
}
class Point {
var x : Number;
var y : Number;
}
var myX = 3.0;
var myY = 3.0;
def pt = bind makePoint(myX, myY);
println(pt.x);
myX = 10.0;
println(pt.x);
scale = 2.0;
println(pt.x);
|
此腳本的輸出如下所示:
讓我們分析一下此腳本(一次分析一部分)。
代碼:
var myX = 3.0;
var myY = 3.0;
def pt = bind makePoint(myX, myY);
println(pt.x);
|
將腳本變量 myX
和 myY
初始化為 3.0
。
這些值隨后作為參數傳遞給 makePoint
函數,該函數會創建并返回一個新的 Point
對象。bind
關鍵字(位于 makePoint
調用前面)將新創建的 Point
對象 (pt
) 綁定到 makePoint
函數的結果。
接下來,代碼:
myX = 10.0;
println(pt.x);
|
將 myX
的值更改為 10.0
并輸出 pt.x
的值。輸出表明 pt.x
現在也為 10.0
。
最后,代碼:
scale = 2.0;
println(pt.x);
|
更改 scale
的值并再次輸出 pt.x
的值。pt.x
的值現在為 20.0
。但是,如果我們從該函數中刪除 bound
關鍵字(從而使其成為非綁定函數),則輸出應為:
這是因為,非綁定函數只是在其某個參數發生變化時才被重新調用。由于 scale
不是函數的參數,因此更改它的值將不會導致另一個函數調用。
您還可以將 bind
與 for
表達式結合使用。為了對此進行研究,讓我們首先定義兩個序列并輸出這兩個序列中各個項的值:
var seq1 = [1..10];
def seq2 = bind for (item in seq1) item*2;
printSeqs();
function printSeqs() {
println("First Sequence:");
for (i in seq1){println(i);}
println("Second Sequence:");
for (i in seq2){println(i);}
}
|
seq1
包含十個項(數字 1 至 10)。seq2
也包含十個項;這些項本來會與 seq1
具有相同的值,但是我們已經對其中的每個項都應用了表達式 item*2
,
因此它們的值將加倍。
因此,輸出為:
First Sequence:
1
2
3
4
5
6
7
8
9
10
Second Sequence:
2
4
6
8
10
12
14
16
18
20
|
我們可以通過將 bind
關鍵字放在 for
關鍵字前面來綁定這兩個序列。
def seq2 = bind for (item in seq1) item*2;
|
問題現在變成:“如果 seq1
發生了某些變化,那么是 seq2
中的所有項都受到影響還是部分項受到影響?”我們可以通過以下方法來對此進行測試:將一個項(值 11)插入
seq1
的末尾處,然后輸出這兩個序列的值,看有什么變化:
var seq1 = [1..10];
def seq2 = bind for (item in seq1) item*2;
insert 11 into seq1;
printSeqs();
function printSeqs() {
println("First Sequence:");
for (i in seq1){println(i);}
println("Second Sequence:");
for (i in seq2){println(i);}
}
|
輸出:
First Sequence:
1
2
3
4
5
6
7
8
9
10
11
Second Sequence:
2
4
6
8
10
12
14
16
18
20
22
|
輸出表明,將 11 插入 seq1
的末尾處不會影響 seq2
中的前 10 個項;新項會自動添加到 seq2
的末尾處,其值為 22。
替換觸發器是附加到變量的任意代碼塊,一旦變量的值發生變化,它們就會執行。以下示例顯示了基本語法:
它定義一個 password
變量并向其附加一個替換觸發器;當密碼發生變化時,該觸發器會輸出一則消息來報告此變量的新值:
var password = "foo" on replace oldValue {
println(""nALERT! Password has changed!");
println("Old Value: {oldValue}");
println("New Value: {password}");
};
password = "bar";
|
此示例的輸出如下所示:
ALERT! Password has changed!
Old Value:
New Value: foo
ALERT! Password has changed!
Old Value: foo
New Value: bar
|
此示例中的觸發器引發兩次:當 password
初始化為 "foo"
時引發一次,當其值變成 "bar" 時又引發一次。請注意,oldValue
變量存儲在調用觸發器之前變量的值。您可以將 oldValue
變量命名為任何所需的名稱,我們是由于該名稱具有描述性才恰好使用它。
天蒼蒼,野茫茫,風吹草底見牛羊