函数方法和函数参数

函数方法

也可以使用def关键字来定义有名字的函数。在Scala 中,使用关键字def 定义函数,其语法格式如下:

def 函数名(参数1:数据类型,参数2:数据类型):函数返回类型= {
    函数体
}

这种方式,通常是用在一个类中,用来定义方法用的。例如,下面定义方法add:

// 定义方法add
def add(x:Int, y:Int):Int = {
    println("这是一个对两个整数进行求和的函数")
    x + y
}

// 通过函数名来调用函数(方法)
add(3,5)

有的方法可以有返回值。在Scala中,函数体的最后一行表达式的值,就是返回值。下面定义一个有返回值的方法:

def func1(name:String, age:Int) : String ={
    println("name=> " + name +"\t age=> " + age)
    "欢迎" + name + "光临, 您的年龄是 => " + age     // 函数的最后一行是返回值
}
func1("张三", 23)

有的方法无返回值。下面定义一个无返回值的方法:

def func2(): Unit ={
    println("这个函数执行没有返回值")
}
func2()

有的方法比较简单,只有一行执行代码,可以写在一行上,称为"单行函数",如下所示:

def printMsg(name:String) = println("Hello, " + name +", welcome happy day!!!")
printMsg("李四")

函数参数

函数定义时指定的参数称为“形参”,函数被调用时实际传入的参数称为“实参”。默认在函数调用时,实参和形参是按顺序一一对应的,否则有可能出现错误。如下代码所示:

def func3(name:String, age:Int) : String = {
    println("name=> " + name + "\t age=> " + age)
    "欢迎" + name + "光临, 您的年龄是 => " + age
}

func3("张三",23)        // OK

// func3(23,"张三")        // 出错,类型不匹配

为了避免这种错误,可以在调用函数时指定参数名称(这称为名称参数),这样就不必一定要按顺序传入实参了。如下代码所示:

func3(age=23, name="张三")     // OK

也可以混用未命名参数和名称参数,只要那些未命名的参数是排在前面的即可:

func3("李四",age=23)

也可以在定义函数时指定默认参数。如果指定了默认参数,那么在调用函数时如果没有为该参数传入实参值,则默认传入的是默认参数。如下所示:

func3(age=23)        // 出错,参数name未给值

下面的代码在定义函数时,为形参指定了默认值,如下:

def func5(name:String="匿名", age:Int=18) : String ={
    println("name=> " + name +"\t age=> " + age)
    "欢迎" + name + "光临, 您的年龄是 => " + age
}

// func5(age=23)
func5()

Scala在定义函数时允许指定最后一个参数可以重复(变长参数),从而允许函数调用者使用变长参数列表来调用该函数。使用可变参数的语法如下:add(a:Int,b:Int,c:Int*)。Scala中使用"*"来指明该参数为变长参数。当它被定义为Int*时,则必须将所有参数作为Int传递。可以将其他参数与可变长度参数一起传递,但是可变长度参数应该是参数列表中的最后一个。函数不能接受两个可变长度参数。

请看下面的代码:

def echo(name:String, age:Int, args:String*) = {
    println(name)
    println(age)
    for (arg <- args) println(arg)
}

echo("张三", 23, "hello", "123", "123", "456")

练习:请定义一个名为add的函数,可以实现对任意多个整数的求各计算。

def add(values:Int*)={
   var sum =0;
   for (value <- values){
      sum = sum+value
   }

   sum
}

val sum = add(1,2,3,4,5,6,7,8,9)
println(s"所有参数的和是: $sum")

在函数内部,变长参数的类型,实际为一个数组,比如上例的String* 类型实际上为Array[String]。然而,如果试图直接传入一个数组类型的参数给这个参数,编译器会报错:

val arrs = Array("hello","吃了吗")
// echo("张三",23,arrs)     // 出错

为了避免这种情况,可以通过在变量后面添加_*来解决,这个符号告诉Scala编译器在传递参数时逐个传入数组的每个元素,而不是数组整体。如下所示:

val arrs = Array("hello","123","123","456")
echo("张三",23, arrs:_*)

《Flink原理深入与编程实战》