定义函数

Table of Contents

1 函数定义

要点如下:

  • 函数参数必须定义参数类型,因为编译器和解析器都无法推断参数类型;
  • 可以指定函数返回类型,Scala 也可以自动推断,但递归函数必须指定返回类型。Unit 类型类似 Java 的 void,表示函数执行有副作用的;
  • 多个表达式用”{…}“包围;
  • 函数如果没有参数,可以不用指定括号:def hello = "hello",调用时也可以不加括号;
  • 如果变量或者函数名和关键字有重复,需要用“`”包围,如 yield 是一个关键字,但也是 Thread 类的一个方法,就需要这样调用:
Thread.`yield`

定义函数的示例:

def sayMsg(msg: String) = {
  println(msg)
}

2 匿名函数

表达式形式:

(参数名: 类型) => 函数体

例:

(a: Int, b: Int) => a + b

3 本地函数

def hello() {
  def hello_world = "hello world"

  println(hello_world)
}

hello()

hello 函数中定义了一个 hello_world 函数,这个函数的作用范围仅在 hello 函数中。

4 函数简短形式

List(1, 2, 3, 5).filter((x) => x % 2 == 0) // 参数 x 不需要指定类型,因为编译器知道 x 必须是整数
List(1, 2, 3, 5).filter(x => x % 2 == 0) // 参数 x 省略了括号
List(1, 2, 3, 5).filter(_ % 2 == 0) // 占位符形式,参数名都省略了

注意占位符形式不能这样用,因为编译器不知道参数类型信息:

val x = _ + _ // error: missing parameter type for expanded function ((x$1: <error>, x$2)

除非指定参数类型:

val x = (_: Int) + (_: Int)

5 偏应用函数

假如定义的函数如下:

def sum(a: Int, b: Int, c: Int) = a + b + c

通过占位符定义一个偏函数:

val sum1 = sum(1, 2, _: Int) // 第三个参数必须指定类型,否则编译器不知道类型
sum1(4) // 7

但是不要这样定义:

val sum1 = sum _

这只是返回了 sum 函数的一个别名,调用还是需要像这样:sum1(1, 2, 3)

6 闭包函数

闭包函数保存了局部信息:

scala> def makeInc(n: Int) = (x: Int) => x + n
makeInc: (n: Int)Int => Int

scala> def inc1 = makeInc(1)
inc1: Int => Int

scala> inc1(2)
res8: Int = 3

7 参数长度可变

在参数后面加“*”:

def echo(args: String*) = for (arg <- args) println(arg)

调用:

scala> echo("1", "2", "3")
1
2
3

如果参数本身就是数组呢,调用方法如下:

echo(Array("1", "2", "3"): _*) // 加“_*”符号

8 命名参数

def echo(msg: String) = println(msg)
echo(msg="hello world")

9 参数默认值

def echo(msg: String = "hello world") = println(msg)

调用如下:

scala> echo()
hello world

scala> echo("hi")
Hi

10 函数作为参数传递

def show(msg: () => String) = println(msg())
show(() => "hello") // 打印 hello

11 Currying函数

def sum1(a: Int)(b: Int) = a + b
sum1(1)(2) // 3

赋值:

val plus1 = sum1(1)_
plus1(10) // 11