Scala的私有字段和定義操作符
私有字段和方法
上一個(gè)版本的Rational類里,我們只是分別用n初始化了numer,用d初始化了denom。結(jié)果,Rational的分子和分母可能比它所需要的要大。例如分?jǐn)?shù) ,可以更約簡化為相同的最簡形式,
,但Rational的主構(gòu)造器當(dāng)前并不做這個(gè)工作:
51CTO編輯推薦:Scala編程語言專題
要想對(duì)分?jǐn)?shù)進(jìn)行約簡化,需要把分子和分母都除以***公約數(shù):greatest common divisor。如:66和42的***公約數(shù)是6。(另一種說法就是,6是能夠除盡66和42的***的整數(shù)。)
- scala> new Rational(66, 42)
- res15: Rational = 66/42


代碼 6.3 帶私有字段和方法的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
- def this(n: Int) = this(n, 1)
- def add(that: Rational): Rational =
- new Rational(
- numer * that.denom + that.numer * denom,
- denom * that.denom
- )
- override def toString = numer+"/"+denom
- private def gcd(a: Int, b: Int): Int =
- if (b == 0) a else gcd(b, a % b)
- }
這個(gè)版本的Rational里,我們添加了私有字段,g,并修改了numer和denom的初始化器(初始化器:initializer是初始化變量,例如初始化numer的“n / g”,的代碼)。因?yàn)間是私有的,它只能在類的主體之內(nèi),而不能在外部被訪問。我們還添加了一個(gè)私有方法,gcd,用來計(jì)算傳入的兩個(gè)Int的***公約數(shù)。比方說,gcd(12, 8)是4。正如你在4.1節(jié)中看到的,想讓一個(gè)字段或方法私有化你只要把private關(guān)鍵字放在定義的前面。私有的“助手方法”gcd的目的是把類的其它部分,這里是主構(gòu)造器,需要的代碼分離出來。為了確保g始終是正的,我們傳入n和d的絕對(duì)值,調(diào)用abs即可獲得任意整數(shù)的絕對(duì)值。
Scala編譯器將把Rational的三個(gè)字段的初始化代碼依照它們在源代碼中出現(xiàn)的次序放入主構(gòu)造器。所以g的初始化代碼,gcd(n.abs, d.abs),將在另外兩個(gè)之前執(zhí)行,因?yàn)樗谠次募谐霈F(xiàn)得最早。g將被初始化為類參數(shù),n和d,的絕對(duì)值的***公約數(shù)。然后再被用于numer和denom的初始化。通過把n和d整除它們的***公約數(shù),g,每個(gè)Rational都將被構(gòu)造成它的最簡形式:
定義操作符 Rational加法的當(dāng)前實(shí)現(xiàn)僅就完成功能來講是沒問題的,但它可以做得更好用。你或許會(huì)問你自己為什么對(duì)于整數(shù)或浮點(diǎn)數(shù)你可以寫成:
- scala> new Rational(66, 42)
- res24: Rational = 11/7
但是如果是分?jǐn)?shù)就必須寫成:
- x + y
或至少是:
- x.add(y)
沒有合理的解釋為什么就必須是這樣的。分?jǐn)?shù)和別的數(shù)應(yīng)該是一樣的。數(shù)學(xué)的角度上看他們甚至比,唔,浮點(diǎn)數(shù),更自然。為什么就不能使用自然的數(shù)學(xué)操作符呢?Scala里面你做得到。本章后續(xù)部分,我們會(huì)告訴你怎么做。
- x add y
***步是用通常的數(shù)學(xué)的符號(hào)替換add方法。這可以直接做到,因?yàn)镾cala里+是合法的標(biāo)識(shí)符。我們可以用+定義方法名。既然已經(jīng)到這兒了,你可以同樣實(shí)現(xiàn)一個(gè)*方法以實(shí)現(xiàn)乘法,結(jié)果展示在代碼6.4中:
代碼 6.4 帶操作符方法的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
- def this(n: Int) = this(n, 1)
- def +(that: Rational): Rational =
- new Rational(
- numer * that.denom + that.numer * denom,
- denom * that.denom
- )
- def *(that: Rational): Rational =
- new Rational(numer * that.numer, denom * that.denom)
- override def toString = numer+"/"+denom
- private def gcd(a: Int, b: Int): Int =
- if (b == 0) a else gcd(b, a % b)
- }
有了這種方式定義的Rational類,你現(xiàn)在可以這么寫了:
與以往一樣,在***輸入的那行里的語法格式相等于一個(gè)方法調(diào)用。你也能這么寫:
- 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
- res32: Rational = 7/6
不過這樣寫可讀性不佳。
- scala> x.+(y)
- res33: Rational = 7/6
另外一件要提的是基于5.8節(jié)中提到的Scala的操作符優(yōu)先級(jí)規(guī)則,Rational里面的*方法要比+方法綁定得更結(jié)實(shí)?;蛘哒f,Rational涉及到+和*操作的表達(dá)式會(huì)按照預(yù)期的方式那樣表現(xiàn)。例如,x + x * y會(huì)當(dāng)作x + (x * y)而不是(x + x) * y:
- scala> x + x * y
- res34: Rational = 5/6
- scala> (x + x) * y
- res35: Rational = 2/3
- scala> x + (x * y)
- res36: Rational = 5/6
【相關(guān)閱讀】