W3Cschool
恭喜您成為首批注冊用戶
獲得88經驗值獎勵
本篇繼續(xù)上一篇,前面我們定義了 Rational 的主構造函數(shù),并檢查了輸入不允許分母為 0。下面我們就可以開始實行兩個 Rational 對象相加的操作。我們需要實現(xiàn)的函數(shù)化對象,因此 Rational 的加法操作應該是返回一個新的 Rational 對象,而不是返回被相加的對象本身。我們很可能寫出如下的實現(xiàn):
class Rational (n:Int, d:Int) {
require(d!=0)
override def toString = n + "/" +d
def add(that:Rational) : Rational =
new Rational(n*that.d + that.n*d,d*that.d)
}
實際上編譯器會給出如下編譯錯誤:
<console>:11: error: value d is not a member of Rational
new Rational(n*that.d + that.n*d,d*that.d)
^
<console>:11: error: value d is not a member of Rational
new Rational(n*that.d + that.n*d,d*that.d)
這是為什么呢?盡管類參數(shù)在新定義的函數(shù)的訪問范圍之內,但僅限于定義類的方法本身(比如之前定義的 toString 方法,可以直接訪問類參數(shù)),但對于 that 來說,無法使用 that.d 來訪問 d. 因為 that 不在定義的類可以訪問的范圍之內。此時需要定類的成員變量。(注:后面定義的 case class 類型編譯器自動把類參數(shù)定義為類的屬性,這是可以使用 that.d 等來訪問類參數(shù))。
修改 Rational 定義,使用成員變量定義如下:
class Rational (n:Int, d:Int) {
require(d!=0)
val number =n
val denom =d
override def toString = number + "/" +denom
def add(that:Rational) =
new Rational(
number * that.denom + that.number* denom,
denom * that.denom
)
}
要注意的我們這里定義成員變量都使用了 val ,因為我們實現(xiàn)的是“immutable”類型的類定義。number 和 denom 以及 add 都可以不定義類型,Scala 編譯能夠根據(jù)上下文推算出它們的類型。
scala> val oneHalf=new Rational(1,2)
oneHalf: Rational = 1/2
scala> val twoThirds=new Rational(2,3)
twoThirds: Rational = 2/3
scala> oneHalf add twoThirds
res0: Rational = 7/6
scala> oneHalf.number
res1: Int = 1
可以看到,這是就可以使用 .number 等來訪問類的成員變量。
Scala 也使用 this 來引用當前對象本身,一般來說訪問類成員時無需使用 this ,比如實現(xiàn)一個 lessThan 方法,下面兩個實現(xiàn)是等效的。
def lessThan(that:Rational) =
this.number * that.denom < that.number * this.denom
和
def lessThan(that:Rational) =
number * that.denom < that.number * denom
但如果需要引用對象自身,this 就無法省略,比如下面實現(xiàn)一個返回兩個 Rational 中比較大的一個值的一個實現(xiàn):
def max(that:Rational) =
if(lessThan(that)) that else this
其中的 this 就無法省略。
在定義類時,很多時候需要定義多個構造函數(shù),在 Scala 中,除主構造函數(shù)之外的構造函數(shù)都稱為輔助構造函數(shù)(或是從構造函數(shù)),比如對于 Rational 類來說,如果定義一個整數(shù),就沒有必要指明分母,此時只要整數(shù)本身就可以定義這個有理數(shù)。我們可以為 Rational 定義一個輔助構造函數(shù),Scala 定義輔助構造函數(shù)使用 this(…)的語法,所有輔助構造函數(shù)名稱為 this。
def this(n:Int) = this(n,1)
所有 Scala 的輔助構造函數(shù)的第一個語句都為調用其它構造函數(shù),也就是 this(…),被調用的構造函數(shù)可以是主構造函數(shù)或是其它構造函數(shù)(最終會調用主構造函數(shù)),這樣使得每個構造函數(shù)最終都會調用主構造函數(shù),從而使得主構造函數(shù)稱為創(chuàng)建類單一入口點。在 Scala 中也只有主構造函數(shù)才能調用基類的構造函數(shù),這種限制有它的優(yōu)點,使得 Scala 構造函數(shù)更加簡潔和提高一致性。
Scala 類定義私有成員的方法也是使用 private 修飾符,為了實現(xiàn) Rational 的規(guī)范化顯示,我們需要使用一個求分子和分母的最大公倍數(shù)的私有方法 gcd。同時我們使用一個私有變量 g 來保存最大公倍數(shù),修改 Rational 的定義:
scala> class Rational (n:Int, d:Int) {
| require(d!=0)
| private val g =gcd (n.abs,d.abs)
| val number =n/g
| val denom =d/g
| override def toString = number + "/" +denom
| def add(that:Rational) =
| new Rational(
| number * that.denom + that.number* denom,
| 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)
| }
defined class Rational
scala> new Rational ( 66,42)
res0: Rational = 11/7
注意 gcd 的定義,因為它是個回溯函數(shù),必須定義返回值類型。Scala 會根據(jù)成員變量出現(xiàn)的順序依次初始化它們,因此g必須出現(xiàn)在 number 和 denom 之前。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: