Scala函数与方法总结
一. 函数调用
Scala 中使用 val 语句可以定义函数,def 语句定义方法。但是在实际应用中,往往会忽略函数和方法的区别而混用了。
class Test{
def m(x: Int) = x + 3 // 方法
val f = (x: Int) => x + 3 // 函数
}
概念: 当⼀个函数⽆需输⼊参数时,我们称这个函数为 “0参函数“,定义⼀个0参函数时,你可以加⼀对空括号,也可以省略掉括号,直接写函数体。
方法调⽤(注意:是方法,不是函数):
- 如果你在定义0参方法时加了括号,则在调⽤时可以加括号或者省略括号。
- 但当你在定义0参方法时没加括号,则在调⽤时不能加括号,只能使⽤函数名。
def m() = {
3
}
println(m()) // 3
println(m) // 3
def f = {
3
}
println(f) // 3
函数调用:定义时有括号,调用是必须有括号。定义时没有括号,调用时必须没有括号。
val fu1 = () => {
100
}
println(fu1()) // 100
val fu2 = {
100
}
println(fu2) // 100
二. 函数定义
- 函数(或方法)内定义函数(或方法),和Python一样,也可以在函数内部定义新的函数,新函数的作用域只在当前函数有效
def calcSalary() = {
def getSalary() = {
10000
}
getSalary * 1.1
}
println(calcSalary)
- 定义函数的方式
// 最简单的写法(指定参数、返回值的类型)
val add6: (Int, Int) => Int = (x: Int, y: Int) => x + y
// 最简单的写法(省略参数、返回值的类型)
val add7 = (x: Int, y: Int) => x + y
// 简版的函数定义,这里的待填空下划线必须给定类型,否则报错。
val add8 = (_: Int) + (_: Int)
add8(3, 4)
res4: Int = 7
- 定义方法的方式
// 标准写法
def add1(x: Int, y: Int): Int = {
return x + y
}
// 返回 x+y
def add2(x: Int, y: Int): Int = {
x + y
}
// 返回 Int
def add3(x: Int, y: Int) = {
x + y
}
// 返回 Unit
def add3(x: Int, y: Int) {
x + y
}
// 无参函数
def getNumber(): Int = 3
def getNumber: Int = 3
def getNumber = 3
// 函数只有一行的写法
def add4(x: Int, y: Int): Int = x + y
// 函数只有一行的写法
def add5(x: Int, y: Int) = x + y
三. 函数作为参数
val n = List(-11, -10, -5, 0, 5, 10)
// 返回大于 0 的数据
n.filter((x: Int) => x > 0)
// 返回大于 0 的数据(简写版本)
n.filter((x) => x > 0)
// 返回大于 0 的数据(简写版本)
n.filter(_ > 0)
四. 部分应用函数
部分应用函数(partially applied function),简单的来说,其实就是先给函数提前确定一些参数的值,这样一来就形成了新的函数,新函数里面会去调用原来的函数,传入原来格式的参数。
部分应用的函数是一个表达式,在这个表达式中,并不给出函数需要的所有参数,而是给出部分,或完全不给。举例来说,要基于 sum创建一个部分应用的函数,假如你不想给出三个参数中的任何一个,可以在"sum"之后放一个下画线,这将返回一个函数,可以被存放到变量中。
def sum(a: Int, b: Int, c: Int) = a + b + c
val a = sum _
a(1, 2, 3)
res1: Int = 6
部分应用函数之所以叫作部分应用函数,是因为你并没有把那个函数应用到所有入参。拿sum _来说,你没有应用任何入参。不过,完全可以通过给出一些必填的参数来表达一个部分应用的函数,比如
val b = sum(1, _: Int, 3)
b: Int => Int = $$Lambda$796/914175168@4ce25e47
b(5)
res2: Int = 9
五. 可变参数列表
要表示这样一个重复参数,需要在参数的类型之后加上一个星号(*)。在函数内部,这个重复参数的类型是一个所声明的参数类型的 Array。因此,在 echo 函数内部,args 的类型其实是 Array[String]
。
// 这样定义以后,echo可以用到零到多个String参数调用
def echo(args: String*) = for (arg <- args) println(arg)
// 尽管如此,如果你有一个合适类型的数组,并尝试将它作为重复参数传入时,你将得到一个编译错误
var arr = Array("What", "are", "you", "doing?")
echo(arr)
// 要完成这样的操作,你需要在数组实参的后面加上冒号和一个_*符号
echo(arr: _*)
// java 中定义可变参数方法
public static void f(int... args) {
for (int i : args) {
System.out.println("i = " + i);
}
}
六. 带默认值的命名参数
带默认值的参数让你可以用不同的顺序将参数传给函数。其语法是简单地在每个实参前加上参数名和等号。位置参数在前,其他的命名参数可以随意调换位置。和Python类似。
def goto_classroom(datetime: String, address: String="room1", username: String="yourself") = {
println(datetime, address, username)
}
goto_classroom("now")
(now,room1,yourself)
goto_classroom("now", username="xiaohong", address="bju")
(now,bju,xiaohong)
七. Scala 函数柯里化(Currying)
函数的柯里化可以固定一些参数,让函数的调用更简单。
首先我们定义一个函数如下:
def add(x:Int,y:Int)=x+y
那么我们应用的时候,应该是这样用:add(1,2),现在我们把这个函数变一下形,那么我们应用的时候,应该是这样用:add(1)(2),最后结果都一样是3,这种方式(过程)就叫柯里化。
def add(x:Int)(y:Int) = x + y
固定函数参数的方式示例
def add(x: Int)(y: Int)(z: Int) = x + y + z
val add1 = add(4)_ // 固定了x为4
val add2 = add1(5) // 固定了x为4, y为5
println(add(4)(5)(6)) // 返回 15
println(add1(5)(6)) // 返回 15
println(add2(6)) // 返回 15