1. 程式人生 > >Scala中的方法&函式的定義

Scala中的方法&函式的定義

作者:林偉兵,叩丁狼高階講師。本文為原創文章,轉載請註明出處。  

4. 方法&函式的定義

在scala中,函式是一等公民,但是一般在開發中,函式和方法是可以相互代替的。

4.1 方法的定義

  1. 一個完整方法的定義如下

    scala> def add(a:Int, b:Int):Int = {
         | return a+b
         | }
    add: (a: Int, b: Int)Int
    
    scala> add(3,5)
    res1: Int = 8
    
  2. 方法的最後一句為返回值的話,可以將return 去掉, 如果一個方法體只有一句程式碼,大括號可以去掉。

    scala> def times(x:Int,y:Int) = x * y
    times: (x: Int, y: Int)Int
    
    scala> times(3,5)
    res0: Int = 15
    
  3. 如果一個方法沒有返回值,其返回型別為Unit , 並且“=”號可以去掉。

    scala> def log(msg:String){
         | println(msg)
         | }
    log: (msg: String)Unit
    
    scala> log("測試")
    測試
    
  4. 返回值的型別也可以通過智慧推導來完成。

4.2 方法轉函式的實現

在方法名後加上“ _ ” ,可以將方法轉換成函式,如下程式碼,<function2>表示函式有2個引數,型別都是Int; 並且有 Int 返回值。

在命令列中,系統會將轉換好的函式賦值給res5 ; 可以通過res5呼叫該函式。    
scala> add2 _
res5: (Int, Int) => Int = <function2>

scala> res5(8,8)
res6: Int = 16

4.3 函式的定義

函式的定義可以在方法的基礎上進行轉換,比如下面程式碼介紹了函式和方法的定義:

## 方法的定義:def 方法名():ReturnType => {}
scala> def times(x:Int, y:Int) => x*y

## 函式的定義: 去掉了def和方法名 這個程式碼塊需要被別人呼叫,所以要用一個變數來引用。
scala> val times=(x:Int, y:Int) => x*y
times: (Int, Int) => Int = <function2>

在函式使用過程中,還有另一個常見的操作,就是將函式作為另一個函式的引數來使用,如下程式碼:

var money =100
def calMoneyLeft():Int = {
    println("函式引數呼叫中")
    money
}

def cost(x: => Int){
    money -=50
    println("函式引數呼叫之前")
    println(x)
}

cost(calMoneyLeft())

4.4 可變引數

對於Java來說,可變引數的宣告的使用如下:

public class Test {
    public static void foo(String... args){

    }

    public static void bar(int... args){

    }

    //我們常見的main函式就是一個帶有可變引數的函式
    public static void main(String... args){
        //可變引數在呼叫的時候可以傳遞一個或者多個引數,也可以不傳遞
        foo("Hello world","Hello Java");
        bar(1,2,3,4);
        bar();
    }
}

scala的可變引數與Java的差不多,只不過把 “…” 改為在型別後面加上“*” 使用如下:

object MultipleArguments {

  def main(args:Array[String]):Unit = {
    println("sum = "+calcSumWithQueue(1,3,5,9,7))
  }

  def calcSumWithQueue(numbers: Int*):Int = {
    var sum = 0
    for (element <- numbers){
      sum+= element
    }
    sum
  }

}

可變引數的位置:

object MultipleArguments {

  //這種寫法沒毛病
  def foo(arg1: Int,arg2: Double*):Unit = { }

  //可變引數後面不能再出現其他引數
  //def foo2(arg1: Double*,arg2: Int):Unit = { }

  //不允許出現多個型別的可變引數
  //def foo3(arg1: Double*,arg2: Int*):Unit = { }

  //總結:一個函式中只能有一個可變引數,並且只能放在引數列表最後
}

可變引數的傳參問題:

object MultipleArguments {

  def main(args: Array[String]): Unit = {
    //可變引數的實參為Range的時候,需要新增:_*來進行資料的轉換
    println("sum = " + calcSumWithQueue(1 to 10: _*))
    //可變引數的實參為Array時,需要新增:_*來進行資料的轉換
    val arr = Array("Hadoop", "Spark", "Storm")
    printArr(arr: _*)
  }

  def calcSumWithQueue(numbers: Int*): Int = {
    var sum = 0
    for (element <- numbers) {
      sum += element
    }
    sum
  }

  def printArr(arr: String*) {
    arr.foreach(ele => println(ele))
  }
}

4.5 引數的預設值

在函式宣告的時候可以為引數設定預設值;在呼叫的時候將真實的值傳遞進去,也可以根據引數的名稱進行傳值:

object ArgWithDefaultVal {

  def main(args: Array[String]):Unit = {
    recordUser()
    recordUser("張三",1.65d)
    //在方法被呼叫的時候,指定要傳入的引數名,這種叫做命名引數
    recordUser(height = 1.55d,name = "李四")
  }

  /*
  *   使用者資訊的錄入
  * */
  def recordUser(name: String="匿名",height: Double=1.70d):Unit = {
    println("錄入使用者記錄 name:"+name+",height:"+height)
  }

}

假如一個方法沒有任何引數,那麼在呼叫的時候,括號是可以去掉的。