Scala 函数笔记
作为面向函数的编程语言,scala函数中传入的参数是不可以直接修改的
方法vs函数
-
方法可以作为一个表达式的一部分出现(调用函数并传参),但是方法(带参方法)不能作为 最终的表达式,但是函数和无参方法可以作为最终的表达式出现。
-
参数列表对于方法是可选的,但是对于函数参数列表是强制的 方法可以没有参数列表,参数列表也可以为空;而函数必须有参数列表(也可以为空)。
-
方法名意味着方法调用,但函数名却代表的是函数自身。
因为方法不能作为最终的表达式存在,所以如果你写了一个方法的名字并且该方法不带参数(没有参数列表或者无参)该表达式的意思是:调用该方法得到最终的表达式。
因为函数可以作为最终表达式出现,如果你写下函数的名字,函数调用并不会发生,该方法自身将作为最终的表达式进行 返回,如果要强制调用一个函数,你必须在函数名后面写()
-
方法可以自动(称之ETA扩展)或手动强制转换为函数;但是函数不可以转换成方法。 在期望出现函数的地方使用方法,该方法自动转换成函数;手动强制转换可以使用 “方法名 _” 转 换成函数
值函数
Scala的语法规定,将函数赋值给变量,并且在函数后面加上空格和下划线的形式成为值函数
def test(str:String){
println(str+":hello")
}
def main(args:Array[String]){
val func=test _;
func("zun");
}
匿名函数
Scala定义匿名函数的语法规则就是,(参数名: 参数类型) => 函数体
将函数赋值给变量,其中3*x被称为字面量
val triple=(x:Double)=>3*x
变长参数
def sum(args: Int*): Int = {
// arg是一个Seq类型
var result = 0
for (arg <- args) {
result += arg
}
result
}
// 1 to 5生成一个Range类型对象,所以使用_*将1 to 5当做参数序列
sum(1 to 5 :_* )
高阶函数
接收其他函数作为参数的函数,也可以将函数作为返回值,被称作高阶函数(higher-order function)
- 高阶函数可以自动推断出参数类型,调用时不需要写明类型
- 对于只有一个参数的函数,调用时还可以省去其小括号
- 如果仅有的一个参数在右侧的函数体内只使用一次,则还可以将接收参数省略,并且将参数用_ 来替代(下图中 main 函数分别展示了高阶函数的这些中写法,大家要熟悉)
高阶函数的意义在哪?虽然减少代码量,可以实现更复杂的功能,但是对于新手来说学习成本高,可维护性低。增加程序员学习成本。
函数组合
def f()=>"hello"
def g()=>"hi"
val fcomg=f _ compose g _
尾递归
在函数尾部调用另一个函数,解决递归的栈溢出问题。
递归是一个不断压栈的过程
使用
@annotation.tailrec
进行检查是否为尾递归
闭包
变量不在有效区域,但是还可以访问,即为闭包
def getGreetingFunc(msg: String) =
(name: String) => println(msg + ", " + name)
//两次调用,分别传入msg,name,第一次执行完之后继续存在创建的函数中
//柯里化形式
def getGreetingFunc(msg: String)(name: String) = println(msg + ", " + name)
//getGreetingFunc("hell0")("scala")
局部函数
即在函数内部定义函数,局部函数可以访问夫函数参数。刚开始时以为局部函数没什么作用。但是后来发现其一大作用就是可以将函数进行二次包装,使函数更加精美。
比如在编写斐波那契函数时,其实可以仅仅使用loop函数完成计算并满足尾递归,但是函数的参数很多。
使用局部函数二次包装之后就显得精美很多
def fib(n: Int): Int = {
@scala.annotation.tailrec
def loop(n: Int, prev: Int, curr: Int): Int =
if (n == 1) prev
else if (n == 2) curr
else loop(n - 1, curr, prev + curr)
loop(n, 0, 1)
}
隐式转换
-
隐式值:省略参数的情况下进行搜索
- 同时出现隐式值、默认值、传值时,编译器的优先级为:传值 >隐式值 >默认值
- 隐式匹配时,不能有二义性
- 如果隐式值、默认值、传值都没有的情况下,使用隐式值的地方便会报错:
-
隐式函数
- 隐式转换函数与函数名无关,只与函数签名(函数参数类型,函数的返回值类型)有关。
- 隐式转换函数是以implicit关键字作用于带有单个参数的函数上。这种函数将会自动应用,将值从一种类型转换 为另外一种类型。
- 隐式转换函数是以implicit关键字作用于带有单个参数的函数上。这种函数将会自动应用,将值从一种类型转换 为另外一种类型。
- 隐式转换函数可以有多个(隐式转换列表),但是需要保证当前环境下只有一个隐式函数被识别。
-
隐式类
隐式类基本介绍 Scala2.10以后提出了隐式类,可以使用implicit声明类,隐式类非常强大,同样可以扩展类的功能,比前面使用 隐式转换丰富类库功能更加方便,在集合中隐式类会发挥重要的作用。
隐式类有如下几个特点:- 构造参数只能有一个
- 必须定义在“类”、“半生对象”、包对象的其中一个里面,即:它不能是一个顶级类。
- 不能是case class(案例类)。
- 作用域内不能有阈值相同名称的标识符。