Scala 方法与函数
Scala 有方法与函数,二者在语义上的区别很小。Scala 方法是类的一部分,而函数是一个对象,可以赋值给一个变量。换句话来说在类中定义的函数即是方法。Scala 中的函数则是一个完整的对象,Scala 中的函数其实就是继承了 Trait 的类的对象。
Scala 中使用 val 语句可以定义函数,def 语句定义方法。
注意:有些翻译上函数(function)与方法(method)是没有区别的。
1、Scala方法/函数定义
object Test {
def main(args: Array[String]): Unit = {
fun(10, 20)
println(sum(10, 20))
println(sum2(30, 20))
}
def fun(a: Int, b: Int) = {
println("a=" + a)
println("b=" + b)
}
def sum(a: Int, b: Int) = a + b
def sum2(a: Int, b: Int): Int ={
return a + b
}
}
-
方法定义由一个 def 关键字开始,紧接着是可选的参数列表,一个冒号 : 和方法的返回类型,一个等于号 = ,最后是方法的主体。
-
如果方法没有返回值,返回类型为 Unit,类似于Java中的 void。方法可以写返回值类型,也可以不写,会自动推断。有时候不能省略,比如在递归函数中、函数的返回类型是函数类型时,方法中写return时等。
-
Scala中有返回值时,可以写return,也可以不写,函数会将最后一行作为结果返回。
-
方法体可以一行搞定时,可以不写 { } 。
-
Scala规定传递给方法的参数都是
常量val
的,不是var的。
2、Scala 函数传名调用(call-by-name)
Scala的解释器在解析函数参数(function arguments)时有两种方式:
- 传值调用(call-by-value):先计算参数表达式的值,再应用到函数内部;
- 传名调用(call-by-name):将未计算的参数表达式直接应用到函数内部
object SayHello {
def main(args: Array[String]): Unit = {
println("传值调用:")
delayed0(time())
println("===================")
println("传名调用:")
delayed(time())
println("===================")
}
def time() = {
println("获取时间,单位为纳秒")
System.nanoTime
}
def delayed0(t : Long)={
println("在 delayed0 方法内")
println("参数"+t)
t
}
def delayed(t: => Long) = {
println("在 delayed 方法内")
println("参数: " + t)
t
}
}
我们声明了 delayed 方法, 该方法在变量名和变量类型使用 => 符号来设置传名调用;输出结果:
传值调用:
获取时间,单位为纳秒
在 delayed0 方法内
参数232873973675933
===================
传名调用:
在 delayed 方法内
获取时间,单位为纳秒
参数: 232873984381351
获取时间,单位为纳秒
===================
简言之,传值调用会在调用方法前将参数的值计算出来,而传名调用则是在方法调用后,在方法内部使用到参数地方调用。
3、Scala 闭包
闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量。
闭包通常来讲可以简单的认为是可以访问一个函数里面局部变量的另外一个函数。
我们引入一个*变量 factor,这个变量定义在函数外面。
这样定义的函数变量 multiplier 成为一个"闭包",因为它引用到函数外面定义的变量,定义这个函数的过程是将这个*变量捕获而构成一个封闭的函数。
实例:
object Test {
def main(args: Array[String]) {
var factor = 3
val multiplier = (i:Int) => i * factor
println( "muliplier(1) value = " + multiplier(1) )
println( "muliplier(2) value = " + multiplier(2) )
}
}
闭包的特性
- 1.函数嵌套函数
- 2.函数内部可以引用外部的参数和变量
- 3.参数和变量不会被垃圾回收机制回收
常见创建闭包的方式 就是函数内创建了函数
- 1.设置私有变量的方法
- 2.不适合的场景:返回闭包的函数是非常大的函数
- 3.缺点常驻内存,会增大内存的使用量,使用不当造成内存泄漏
为什么要使用闭包
- 1.想要得到函数内部的局部变量
- 2.只有函数内部的子函数才能读取的函数内部的局部变量
- 3.闭包是函数内部和函数外部链接的桥梁
闭包的用途
- 可以读取函数内部变量,可以让变量的值始终保存在内存中
4、递归函数
必须制定 函数的返回类型
def fun(num :Int) :Int= {
if(num ==1)
num
else
num * fun2(num-1)
}
print(fun(4))
5、Scala 函数 - 默认参数值
object Test {
def main(args: Array[String]) {
println( "返回值 : " + addInt() );
}
def addInt( a:Int=5, b:Int=7 ) : Int = {
var sum:Int = 0
sum = a + b
return sum
}
}
6、Scala 函数 - 可变参数
Scala 通过在参数的类型之后放一个星号来设置可变参数(可重复的参数)。
object Test {
def main(args: Array[String]) {
printStrings("I", "Love", "Scala");
}
def printStrings( args:String* ) = {
var i : Int = 0;
for( arg <- args ){
println("Arg value[" + i + "] = " + arg );
i = i + 1;
}
}
}
7、Scala 函数 - 匿名函数
Scala 中定义匿名函数的语法很简单,箭头左边是参数列表,右边是函数体。
def main(args: Array[String]): Unit = {
value1()
value2(2)
println(value3(3,4))
println(value4(4,5))
}
// 无参匿名函数
val value1 = () => {
println("Hello word")
}
// 有参匿名函数
val value2 = (a: Int) => {
println(a)
}
// 多参 有返回
val value3 = (a: Int, b: Int) => {
a * b
}
val value4 = (a: Int, b: Int) => a * b
8、Scala 高阶函数
高阶函数(Higher-Order Function)就是操作其他函数的函数。
Scala 中允许使用高阶函数, 高阶函数可以使用其他函数作为参数,或者使用函数作为输出结果。
以下实例中,apply() 函数使用了另外一个函数 f 和 值 v 作为参数,而函数 f 又调用了参数 v:
object Test {
def main(args: Array[String]) {
println( apply( layout, 10) )
}
// 函数 f 和 值 v 作为参数,而函数 f 又调用了参数 v
def apply(f: Int => String, v: Int) = f(v)
def layout[A](x: A) = "[" + x.toString() + "]"
}
apply()中 f 使用=>String, 表示是函数的传名调用,传入的函数会在该函数体使用的位置调用。