Scala編程實(shí)例:帶類型的參數(shù)化數(shù)組
Scala里可以使用new實(shí)例化對(duì)象或類實(shí)例。當(dāng)你在Scala里實(shí)例化對(duì)象,可以使用值和類型把它參數(shù)化:parameterize。參數(shù)化的意思是在你創(chuàng)建實(shí)例的時(shí)候“設(shè)置”它。通過把加在括號(hào)里的對(duì)象傳遞給實(shí)例的構(gòu)造器的方式來用值參數(shù)化實(shí)例。
51CTO編輯推薦:Scala編程語言專題
例如,下面的Scala代碼實(shí)例化一個(gè)新的java.math.BigInteger并使用值"12345"參數(shù)化:
- val big = new java.math.BigInteger("12345")
通過在方括號(hào)里設(shè)定一個(gè)或更多類型來參數(shù)化實(shí)例。代碼3.1里展示了一個(gè)例子。在這個(gè)例子中,greetStrings是類型Array[String](字串?dāng)?shù)組)的值,并被第一行代碼里的值3參數(shù)化,使它的初始長度為3。如果把代碼3.1里的代碼作為腳本執(zhí)行,你會(huì)看到另一個(gè)Hello, world!的祝詞。請(qǐng)注意當(dāng)你同時(shí)用類型和值去參數(shù)化實(shí)例的時(shí)候,類型首先在方括號(hào)中出現(xiàn),然后跟著值在圓括號(hào)中。
- val greetStrings = new Array[String](3)
- greetStrings(0) = "Hello"
- greetStrings(1) = ", "
- greetStrings(2) = "world!\n"
- for (i <- 0 to 2)
- print(greetStrings(i))
代碼 3.1 用類型參數(shù)化數(shù)組
注意
盡管代碼3.1里的代碼演示了一些重要的概念,但它沒有展示Scala里創(chuàng)建和初始化數(shù)組的推薦方式。你會(huì)在代碼3.2中看到更好的方式。
如果想用一種更顯式的方式,你可以顯式定義greetStrings的類型:
- val greetStrings: Array[String] = new Array[String](3)
由于Scala有類型推斷,這行代碼與代碼3.1里的第一行代碼語義一致。不過這種形式說明了類型參數(shù)化部分(方括號(hào)里的類型名)形成了實(shí)例類型的部分,而值參數(shù)化部分(圓括號(hào)里的值)不是。greetStrings的類型是Array[String],不是Array[String](3)。
代碼3.1的下三行代碼初始化了greetStrings數(shù)組的每個(gè)元素:
- greetStrings(0) = "Hello"
- greetStrings(1) = ", "
- greetStrings(2) = "world!\n"
正如前面提到的,Scala里的數(shù)組是通過把索引放在圓括號(hào)里面訪問的,而不是像Java那樣放在方括號(hào)里。所以數(shù)組的第零個(gè)元素是greetStrings(0),不是greetStrings[0]。
這三行代碼演示了搞明白Scala如何看待val的意義的重要概念。當(dāng)你用val定義一個(gè)變量,那么這個(gè)變量就不能重新賦值,但它指向的對(duì)象卻仍可以暗自改變。所以在本例中,你不能把greetStrings重新賦值成不同的數(shù)組;greetStrings將永遠(yuǎn)指向那個(gè)它被初始化時(shí)候指向的同一個(gè)Array[String]實(shí)例。但是你能一遍遍修改那個(gè)Array[String]的元素,因此數(shù)組本身是可變的。
代碼3.1的最后兩行包含一個(gè)for表達(dá)式用來依次輸出每個(gè)greetStrings數(shù)組元素。
- for (i <- 0 to 2)
- print(greetStrings(i))
這個(gè)for表達(dá)式的第一行代碼演示了Scala的另一個(gè)通用規(guī)則:如果方法僅帶一個(gè)參數(shù),你可以不帶點(diǎn)或括號(hào)的調(diào)用它。本例中的to實(shí)際上是帶一個(gè)Int參數(shù)的方法。代碼0 to 2被轉(zhuǎn)換成方法調(diào)用(0).to(2)。 請(qǐng)注意這個(gè)語法僅在你顯示指定方法調(diào)用的接受者時(shí)才起作用。不可以寫 pringln 10,但是可以寫成“Console println 10”。
從技術(shù)上講,Scala沒有操作符重載,因?yàn)樗緵]有傳統(tǒng)意義上的操作符。取而代之的是,諸如+,-,*和/這樣的字符可以用來做方法名。因此,當(dāng)?shù)谝徊嚼锬阍赟cala解釋器里輸入1 + 2,你實(shí)際上正在Int對(duì)象1上調(diào)用一個(gè)名為+的方法,并把2當(dāng)作參數(shù)傳給它。如圖3.1所示,你也可以使用傳統(tǒng)的方法調(diào)用語法把1 + 2替代寫成(1).+(2)。
這里演示的另一重要思想可以讓你看到為什么數(shù)組在Scala里是用括號(hào)訪問的。與Java比Scala很少有特例。數(shù)組和Scala里其他的類一樣只是類的實(shí)現(xiàn)。當(dāng)你在一個(gè)或多個(gè)值或變量外使用括號(hào)時(shí),Scala會(huì)把它轉(zhuǎn)換成對(duì)名為apply的方法調(diào)用。于是greetStrings(i)轉(zhuǎn)換成greetStrings.apply(i)。所以Scala里訪問數(shù)組的元素也只不過是跟其它的一樣的方法調(diào)用。這個(gè)原則不僅僅局限于數(shù)組:任何對(duì)某些在括號(hào)中的參數(shù)的對(duì)象的應(yīng)用將都被轉(zhuǎn)換為對(duì)apply方法的調(diào)用。當(dāng)然前提是這個(gè)類型實(shí)際定義過apply方法。所以這不是一個(gè)特例,而是一個(gè)通則。
與之相似的是,當(dāng)對(duì)帶有括號(hào)并包括一到若干參數(shù)的變量賦值時(shí),編譯器將把它轉(zhuǎn)化為對(duì)帶有括號(hào)里參數(shù)和等號(hào)右邊的對(duì)象的update方法的調(diào)用。
例如,
- greetStrings(0) = "Hello"
將被轉(zhuǎn)化為
- greetStrings.update(0, "Hello")
因此,下列Scala代碼與你在代碼3.1里的代碼語義一致:
- val greetStrings = new Array[String](3)
- greetStrings.update(0, "Hello")
- greetStrings.update(1, ", ")
- greetStrings.update(2, "world!\n")
- for (i <- 0.to(2))
- print(greetStrings.apply(i))
Scala在對(duì)待任何事上追求概念的簡(jiǎn)潔性,從數(shù)組到表達(dá)式,包括帶有方法的對(duì)象。你不必記住太多特例,如Java里原始類型和相應(yīng)的包裝類間的,或者數(shù)組和正常的對(duì)象間的差別。而且這種統(tǒng)一并未損害重要的性能代價(jià)。Scala編譯器使用Java數(shù)組,原始類型,及可存在于編譯完成代碼里的原生數(shù)學(xué)類型。
盡管目前為止在這一步里你看到的例子編譯運(yùn)行良好,Scala提供了通??梢杂迷谀阏鎸?shí)代碼里的更簡(jiǎn)潔的方法創(chuàng)造和初始化數(shù)組。它看起來就像展示在代碼3.2中的樣子。這行代碼創(chuàng)建了長度為3的新數(shù)組,用傳入的字串"zero","one"和"two"初始化。編譯器推斷數(shù)組的類型是Array[String] ,因?yàn)槟惆炎执畟鹘o它。
- val numNames = Array("zero", "one", "two")
代碼 3.2 創(chuàng)造和初始化數(shù)組
你在代碼3.2里實(shí)際做的就是調(diào)用了一個(gè)叫做apply的工廠方法,從而創(chuàng)造并返回了新的數(shù)組。apply方法帶可變數(shù)量個(gè)參數(shù) ,被定義在Array的伴生對(duì)象:companion object上。你會(huì)在4.3節(jié)里學(xué)到更多關(guān)于伴生對(duì)象的東西。如果你是一個(gè)Java程序員,你可以認(rèn)為這個(gè)就像在Array類上調(diào)用一個(gè)叫做apply的靜態(tài)方法。更羅嗦的調(diào)用同樣的apply方法的辦法是:
- val numNames2 = Array.apply("zero", "one", "two")
本文節(jié)選自《Programming in Scala》
【相關(guān)閱讀】