scala學習-介紹scala的幾種特性7

承接上篇,前提條件檢查,使用require。
1添加成員變量
記得上篇的時候,使用了類參數的方式來構建主構造函數,但是這是由缺陷的。
現在我們構建一個兩個rational相加的操作。

class Rational (n:Int,d:Int){
  println("i am a class construction~"+n+"/"+d)
  require(d!=0)
  override def  toString = n+"/"+d

  def add(that:Rational):Rational = {
    new Rational (n*that.d + that.n*d,d*that.d)
  }
}

這裏寫圖片描述
這裏編譯都通不過的,爲什麼呢?在新定義的方法add中,是可以訪問n和d的。但是對於that來說,無法使用that.d來訪問d,因爲that不再定義的類的訪問範圍之類。這也表明,d和n不能作爲類Rational的成員變量,這是要定義成員變量了。做如下修改:

class Rational (n:Int,d:Int){
  println("i am a class construction~"+n+"/"+d)
  require(d!=0)
  val num=n
  val denom=d
  override def  toString = n+"/"+d
  def add(that:Rational):Rational = {
    new Rational (n*that.denom + that.num*d,d*that.denom)
  }
}

注意下的是,這裏我們使用了val,因爲我們要實現的是immutable的類定義。還有就是num,denom都用定義類型,其實add也不用,但是個人喜歡定義出來,方便閱讀。
2引用自身
Scala中也可以使用this,和java的使用方式是一樣的,是代表當前的對象,比如實現一個Rational是否小與另一個。

def lessthan(that:Rational)={
    this.num*that.denom<that.num*this.denom
  }
  def lessthan2(that:Rational)={
    num*that.denom<that.num*denom
  }

3輔助構造函數
以前我們說過,主構造函數,而且除了方法,整個類都會運行一次。除了主構造函數之外的構造函數,都叫做輔助構造函數。
這裏定義一個Rational的輔佐構造函數,scala構造輔佐構造函數的語法爲this(),且所有輔佐構造函數的語法都是這樣。
所有輔佐構造函數的第一個語句都要調用其他的構造函數,不論是輔助構造函數還是主構造函數,這樣設計的原因是,一個構造函數最後都會調用到主構造函數,使得主構造函數成爲創建類對象的一個單一入口。提高一致性。
4私有成員和私有方法
和java一樣都是使用private來修飾的,含義都是一樣的。下面定義一個私有方法,求分子分母的最大公倍數。

class Rational (n:Int,d:Int){
  println("i am a class construction~"+n+"/"+d)
  require(d!=0)
    private val g = gcd(n,d)
  val num=n/g
  val denom=d/g
  override def  toString = n+"/"+d
  def add(that:Rational):Rational = {
    new Rational (n*that.denom + that.num*d,d*that.denom)
  }
  def lessthan(that:Rational)={
    this.num*that.denom<that.num*this.denom
  }
  def lessthan2(that:Rational)={
    num*that.denom<that.num*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)

}

自身調用自身,一定要加返回類型,其實,習慣還是加返回類型把,減少錯誤。還有要注意一點,scala中是按照順序來初始化變量的,所以g變量要放在Num和denom之前。
5定義運算符
以前我們說過,在scala中運算符其實也就是一個方法而已,沒有什麼特殊,在上面的列子中,我們定義了一個add方法,你可以x.add(y),也可以x add y,使用,但是我們還可以直接使用+,-來做操作。

def +(that:Rational)={
        new Rational (n*that.denom + that.num*d,d*that.denom)
     }

這裏寫圖片描述
這裏的”i am a class^^”運行了3次,是因爲new Rational了三次,運行了裏面的println方法。
可以使用相同的方式擴展-,/,*等運算符的用法。
6標識符
其實和java比較相似,字符數據和符號,字符或者以下劃線開始。符號的話,避免使用$符號,這是scala在編譯時,有些時候要使用的,所以我們避免使用。其實習慣還是以字符開始,做了那麼久項目還沒遇見過以符號開始的規範。還是以駝峯結構。
這裏寫圖片描述
還有這種混合的,字符和符號
7方法重載
和java一樣,重載就是方法名相同,參數不同,假如我想,一個Rational可以和一個Int相加。可以這樣

def +(that:Int)={
    new Rational(num+that*denom,denom)
  }```

val x = new Rational(2,1)
println(x+5)
“`
和java是一樣的。
8隱式類型轉換-這個比較重要
我們剛纔定義了rational+Int,可以解決x+2的問題,但是如果是2+x呢,因爲2是Int類型,Int類型沒有支持相加的方法?這怎麼辦?1修改Int源碼,加重載其+方法(想想也不可能用這種方法)。2通過靜態擴展方法來實現,就是隱式類型轉換。就是如果遇到2+x這種情況,Int沒有這種方法,就把這個Int類型的實列轉換成Rational類型。
scala中是通過implicit def來定義。
這裏寫圖片描述
在eclipse中和教程說的不一樣,我暈了個去了……是怎麼回事呢?
但是在命令行環境是可以的。我個人覺得是這麼回事,eclipse的編譯scala的問題。原本編譯器看見z+x的時候,發現Int沒有+Rational的方法,它是要報錯的,但是在它報錯之前,會檢測當前的作用域,發現了intToRational的方法,所以把它編譯成了intToRational(z)+x。
估計eclipse編譯的時候,有問題,所以纔回出現這種情況。以後在研究下。
隱含類型轉換在scala編程中,十分重要。

發佈了26 篇原創文章 · 獲贊 20 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章