1. 程式人生 > 實用技巧 >Scala:(四) 方法、函式、Trait

Scala:(四) 方法、函式、Trait

scala中既有函式也有方法,在大多數情況下,不用理會其區別也可正常使用。但有時候還是要區分其異同。
Scala 有方法與函式,二者在語義上的區別很小。Scala 方法是類的一部分,而函式是一個物件可以賦值給一個變數。換句話來說在類中定義的函式即是方法。

有些翻譯上函式(function)與方法(method)是沒有區別的。在寫這篇部落格的過程中,也參考了一些資料,但大都不能令我滿意。所以,知道即可,不要過於追究這勞什子,scala是一門語言,語言自然以使用為第一要務。

方法

Scala中的方法跟Java的方法一樣,方法是組成類的一部分。方法有名字、型別簽名,有時方法上還有註解,以及方法的功能實現程式碼(位元組碼)
我們來定義看一個最經典的方法

函式

再來定義一個函式

其主要區別為:

在函數語言程式設計語言中,函式是“頭等公民”,它可以像任何其他資料型別一樣被傳遞和操作
函式定義語法 用def來定義
可以定義傳入的引數,要指定傳入引數的型別
方法可以寫返回值的型別也可以不寫,會自動推斷,有時候不能省略,必須寫,比如在遞迴函式中或者函式的返回值是函式型別的時候。
scala中函式有返回值時,可以寫return,也可以不寫return,會把函式中最後一行當做結果返回。當寫return時,必須要寫函式的返回值。
如果返回值可以一行搞定,可以將{}省略不寫
傳遞給方法的引數可以在方法中使用,並且scala規定方法的傳過來的引數為val的,不是var的。
如果去掉方法體前面的等號,那麼這個方法返回型別必定是Unit的。這種說法無論方法體裡面什麼邏輯都成立,scala可以把任意型別轉換為Unit.假設,裡面的邏輯最後返回了一個string,那麼這個返回值會被轉換成Unit,並且值會被丟棄。
函式也可作為引數傳遞到方法裡

方法也可轉為函式

方法及函式的呼叫

基本使用與java也類似。同樣可以點出來,各種操作符也是可以使用的。
Scala中的+ - * / %等操作符的作用與Java一樣,位操作符 & | ^ >> <<也一樣。只是有一點特別的:這些操作符實際上是方法。

a + b
是如下方法呼叫的簡寫:
a.+(b)
a 方法 b可以寫成 a.方法(b)

遞迴函式

注:遞迴函式的返回值是必須寫的

    /**
     * 遞迴函式 
     * 5的階乘
     */
    def fun2(num :Int) :Int= {
      if(num == 1)
        num
      else 
        num * fun2(num-1)  //將函式也作為返回值,直到 num==1
    }
    print(fun2(5))

引數預設值及可變形參

scala與java類似,引數同樣可以有預設值,且引數個數也可以是不定的

預設值的函式中,如果傳入的引數個數與函式定義相同,則傳入的數值會覆蓋預設值。
如果不想覆蓋預設值,傳入的引數個數小於定義的函式的引數,則需要指定引數名稱。

def fun3(a :Int = 10,b:Int) = {
      println(a+b)
    }
    fun3(b=2)

對於引數不定的,引數之間要用逗號隔開

def fun4(elements :Int*)={
      var sum = 0;
      for(elem <- elements){
        sum += elem
      }
      sum
    }
    println(fun4(1,2,3,4))

Trait

Scala Trait(特徵) 相當於 Java 的介面,實際上它比介面還功能強大。與介面不同的是,它還可以定義屬性和方法的實現
這裡的trait字面意思是特質或者特徵,這個詞翻譯成特徵比較合適。它的意義和java,c#中介面很類似。但是trait支援部分實現,也就是說可以在scala的trait中可以實現部分方法。
一般情況下Scala的類可以繼承多個Trait,從結果來看就是實現了多重繼承。Trait(特徵) 定義的方式與類類似,但它使用的關鍵字是 trait。
繼承的多個trait中如果有同名的方法和屬性,必須要在類中使用“override”重新定義。
trait中不可以傳引數

trait Read {
  val readType = "Read"
  val gender = "m"
  def read(name:String){
	println(name+" is reading")
  }
}

trait Listen {
  val listenType = "Listen"
  val gender = "m"
  def listen(name:String){
	println(name + " is listenning")
  }
}

class Person() extends Read with Listen{
  override val gender = "f"
}

object test {
  def main(args: Array[String]): Unit = {
    val person = new Person()
    person.read("zhangsan")
    person.listen("lisi")
    println(person.listenType)
    println(person.readType)
    println(person.gender)
    
  }
}

一下引用菜鳥教程的部分內容,原文摘錄:

/* 檔名:Test.scala
 * author:菜鳥教程
 * url:www.runoob.com
 */
trait Equal {
  def isEqual(x: Any): Boolean
  def isNotEqual(x: Any): Boolean = !isEqual(x)
}

class Point(xc: Int, yc: Int) extends Equal {
  var x: Int = xc
  var y: Int = yc
  def isEqual(obj: Any) =
    obj.isInstanceOf[Point] &&
    obj.asInstanceOf[Point].x == x
}

object Test {
   def main(args: Array[String]) {
      val p1 = new Point(2, 3)
      val p2 = new Point(2, 4)
      val p3 = new Point(3, 3)

      println(p1.isNotEqual(p2))
      println(p1.isNotEqual(p3))
      println(p1.isNotEqual(2))
   }
}

執行結果為:

false
true
true