鍍金池/ 教程/ Scala/ 類和對象 (五)
包對象
Ordered Trait
組合和繼承–定義 final 成員
基本數(shù)據(jù)類型
Match 表達式
類和對象 (三)
操作基本數(shù)據(jù)類型
for 表達式
組合和繼承–重載成員函數(shù)和方法
類和對象 (二)
組合和繼承–定義 factory 對象
組合和繼承–多態(tài)和動態(tài)綁定
Trait 的基本概念
if 表達式
組合和繼承–抽象類
函數(shù)–函數(shù)字面量的一些簡化寫法
while 循環(huán)
組合和繼承–使用組合還是繼承?
訪問控制修飾符
Trait 示例–Rectangular 對象
組合和繼承–定義參數(shù)化成員變量
組合和繼承–定義無參數(shù)方法
類和對象 (一)
函數(shù)–閉包
函數(shù)–類成員函數(shù)
Scala 基本數(shù)據(jù)類型的實現(xiàn)方法
try 表達式處理異常
選擇瘦接口還是胖接口設(shè)計?
組合和繼承–小結(jié)
創(chuàng)建新的控制結(jié)構(gòu)
使用 import
為訪問控制修飾符添加作用域
Scala 的類層次關(guān)系
類和對象 (五)
傳名參數(shù)
柯里化函數(shù)
函數(shù)–頭等公民
組合和組合和繼承–定義 heighten 和 widen 函數(shù)
使用 Package–將代碼放入包中
隱含的 import
所有類的公共子類–底層類型
進一步 Scala
函數(shù)–局部函數(shù)
引用包中的代碼
組合和繼承–使用 override 修飾符
組合和繼承–實現(xiàn)類 Element 的 above,beside 和 toString()方法
類和對象 (四)
函數(shù)–尾遞歸
沒有“break”和“continue”的日子
組合和繼承–調(diào)用基類構(gòu)造函數(shù)
減低代碼重復
函數(shù)–函數(shù)–可變參數(shù),命名參數(shù),缺省參數(shù)
起步 Scala
組合和繼承–擴展類
函數(shù)–部分應用的函數(shù)
開始神奇的 Scala編程之旅
組合和繼承–概述
Trait 用來實現(xiàn)可疊加的修改操作

類和對象 (五)

定義運算符

本篇還將接著上篇 Rational 類,我們使用 add 定義兩個 Rational 對象的加法。兩個 Rational 加法可以寫成 x.add(y)或者 x add y 即使使用 x add y 還是沒有 x + y 來得簡潔。

我們前面說過在 Scala 中運算符(操作符)和普通的方法沒有什么區(qū)別,任何方法都可以寫成操作符的語法。比如:上面的 x add y。而在 Scala 中對方法的名稱也沒有什么特別的限制,你可以使用符號作為類方法的名稱,比如使用+,- * 等符號。因此我們可以重新定義 Rational 如下:

class Rational (n:Int, d:Int) {
   require(d!=0)
   private val g =gcd (n.abs,d.abs) 
   val numer =n/g 
   val denom =d/g 
   override def toString = numer + "/" +denom
   def +(that:Rational)  =
     new Rational( 
       numer * that.denom + that.numer* denom,
       denom * that.denom 
     ) 
   def * (that:Rational) =
     new Rational( numer * that.numer, denom * that.denom)
   def this(n:Int) = this(n,1) 
   private def gcd(a:Int,b:Int):Int =
     if(b==0) a else gcd(b, a % b)
}

這樣就可以使用 + , 號來實現(xiàn) Rational 的加法和乘法。+,*的優(yōu)先級是 Scala 預定的,和整數(shù)的+,-, ,/的優(yōu)先級一樣。下面為使用 Rational 的例子:

scala> val x= new Rational(1,2)
x: Rational = 1/2
scala> val y=new Rational(2,3)
y: Rational = 2/3
scala> x+y
res0: Rational = 7/6
scala> x+ x*y
res1: Rational = 5/6

從這個例子也可以看出 Scala 語言的擴展性,你使用 Rational 對象就像 Scala 內(nèi)置的數(shù)據(jù)類型一樣。

Scala中的標識符

從前面的例子我們可以看到 Scala 可以使用兩種形式的標志符,字符數(shù)字和符號。字符數(shù)字使用字母或是下劃線開頭,后面可以接字母或是數(shù)字,符號”$”在 Scala 中也看作為字母。然而以“$”開頭的標識符為保留的 Scala 編譯器產(chǎn)生的標志符使用,應用程序應該避免使用“$”開始的標識符,以免造成沖突。

Scala 的命名規(guī)則采用和 Java 類似的 camel 命名規(guī)則,首字符小寫,比如 toString。類名的首字符還是使用大寫。此外也應該避免使用以下劃線結(jié)尾的標志符以避免沖突。符號標志符包含一個或多個符號,如+,:,? 等,比如:

+ ++ ::: < ?> :->

Scala 內(nèi)部實現(xiàn)時會使用轉(zhuǎn)義的標志符,比如:-> 使用 $colon$minus$greater 來表示這個符號。因此如果你需要在 Java 代碼中訪問:->方法,你需要使用 Scala 的內(nèi)部名稱 $colon$minus$greater。

混合標志符由字符數(shù)字標志符后面跟著一個或多個符號組成,比如 unary_+ 為 Scala 對+方法的內(nèi)部實現(xiàn)時的名稱。字面量標志符為使用“定義的字符串,比如 `x` `yield`。你可以在“之間使用任何有效的 Scala 標志符,Scala 將它們解釋為一個 Scala 標志符,一個典型的使用為 Thread 的 yield 方法, 在 Scala 中你不能使用 Thread.yield()是因為 yield 為 Scala 中的關(guān)鍵字, 你必須使用 Thread.`yield`()來使用這個方法。

方法重載

和 Java 一樣,Scala 也支持方法重載,重載的方法參數(shù)類型不同而使用同樣的方法名稱,比如對于 Rational 對象,+的對象可以為另外一個 Rational 對象,也可以為一個 Int 對象,此時你可以重載+方法以支持和 Int 相加。

def + (i:Int) =
     new Rational (numer + i * denom, denom)

隱式類型轉(zhuǎn)換

上面我們定義 Rational 的加法,并重載+以支持整數(shù),r + 2 ,當如果我們需要 2 + r 如何呢? 下面的例子:

scala> val x =new Rational(2,3)
x: Rational = 2/3
scala> val y = new Rational(3,7)
y: Rational = 3/7
scala> val z = 4
z: Int = 4
scala> x + z
res0: Rational = 14/3
scala> x + 3
res1: Rational = 11/3
scala> 3 + x
<console>:10: error: overloaded method value + with alternatives:
  (x: Double)Double <and>
  (x: Float)Float <and>
  (x: Long)Long <and>
  (x: Int)Int <and>
  (x: Char)Int <and>
  (x: Short)Int <and>
  (x: Byte)Int <and>
  (x: String)String
 cannot be applied to (Rational)
              3 + x
                ^

可以看到 x+3 沒有問題,3 + x 就報錯了,這是因為整數(shù)類型不支持和 Rational 相加。我們不可能去修改 Int 的定義(除非你重寫 Scala 的 Int 定義)以支持 Int 和 Rational 相加。如果你寫過 .Net 代碼,這可以通過靜態(tài)擴展方法來實現(xiàn),Scala 提供了類似的機制來解決這種問題。如果 Int 類型能夠根據(jù)需要自動轉(zhuǎn)換為 Rational 類型,那么 3 + x 就可以相加。Scala 通過 implicit def 定義一個隱含類型轉(zhuǎn)換,比如定義由整數(shù)到 Rational 類型的轉(zhuǎn)換如下:

implicit def intToRational(x:Int) = new Rational(x)

再重新計算 r+2 和 2 + r 的例子:

scala> val r = new Rational(2,3)
r: Rational = 2/3
scala> r + 2
res0: Rational = 8/3
scala> 2 + r
res1: Rational = 8/3

其實此時 Rational 的一個+重載方法是多余的, 當 Scala 計算 2+ r,發(fā)現(xiàn) 2(Int)類型沒有 可以和 Rational 對象相加的方法,Scala 環(huán)境就檢查 Int 的隱含類型轉(zhuǎn)換方法是否有合適的類型轉(zhuǎn)換方法,類型轉(zhuǎn)換后的類型支持+r,一檢查發(fā)現(xiàn)定義了由 Int 到 Rational 的隱含轉(zhuǎn)換方法,就自動調(diào)用該方法,把整數(shù)轉(zhuǎn)換為 Rational 數(shù)據(jù)類型,然后調(diào)用 Rational 對象的+ 方法。從而實現(xiàn)了 Rational 類或是 Int 類的擴展。關(guān)于 implicit def 的詳細介紹將由后面的文章來說明,隱含類型轉(zhuǎn)換在設(shè)計 Scala 庫時非常有用。