Scala有方法和函数之分;
Scala方法是类的一部分,而函数是一个对象可以赋值给一个变量;方法和函数的主要差别在于是否在类中定义,且函数可作为一个参数传入到方法中,而方法不行,在Scala中无法直接操作方法,必须先将其转换成函数;
Scala方法声明
Scala方法声明格式:
def functionName ([参数列表]):[return type] //定义抽象方法
def funtionName ([参数列表]):[return type] = {
//方法体
return typeValue
} // 定义方法
// 对于无返回值的方法,可以返回Unit,这个类似于C#的void
Scala方法使用实例
object FunctionExamples{
def Add(a:Int,b:Int):Int = {
return a + b
} // 有输入有返回值的方法
def HelloWorld():Unit = {
println("Hello World")
} // 无输入无返回值的方法
}
Scala方法调用
// 方法调用
functionName( //参数列表)
[instance.]functionName(//参数列表)
object Test{
def main(args:Array[String]){
println("Return Value:" + Add(5,7);
}
def Add(a:Int,b:Int):Int = {
return a + b
} // 有输入有返回值的方法
}
Scala函数声明
传名调用
Scala的解释器在解析函数参数(function arguments)时有两种方式:
- 传值调用(call-by-value):先计算参数表达式的值,再应用到函数内部;
- 传名调用(call-by-name):将未计算的参数表达式直接应用到函数内部;
在进入函数内部前,传值调用方式就已经将参数表达式的值计算完毕,而传名调用是在函数内部进行参数表达式的值计算的;这就造成了一种现象,每次使用传名调用时,解释器都会计算一次表达式的值;
object Test{
def main(args:Array[String]){
delay(time()) // 可以直接将参数当成一个函数使用
}
def time() = {
println("获取时间,单位为纳秒")
return System.nanoTime
}
def delayed( t : => Long) => {
println("在delayed方法内")
println("参数:" + t)
return t
} // 设置传名调用,该方法在变量名和变量类型使用 =>符号来
//设置传名调用
}
// 运行输出
在delayed方法内
获取时间,单位为纳秒
参数:241550840475831
获取时间,单位为纳秒
//运行过程分析
//该实例中,delay方法打印了一条信息表示进入了该方法,接着
//delay方法打印接收到的值,而由于传名函数时在函数内部进行参数
//表达式的值计算的,因此会先输出“获取时间,单位为纳秒”
//然后参数t就会传入delay方法中,输出“参数:”
//在返回t时,由于传名函数特性,则会继续计算time()方法
可变参数
Scala允许指明函数的最后一个参数可以是重复的,即我们不需要指定函数参数的个数,可以向函数传入可变长度参数列表。
Scala通过在参数的类型之后放一个星号来设置可变参数(可重复的参数)
object Test{
def main(args:Array[String]){
printString("Runoob","Scala","Python");
}
def printString(args:String*) = {
var i:Int = 0;
for( arg <- args){
println("Arg value[" + i +"] = " +arg);
i = i + 1;
}
}
}
指定参数名和默认参数值
一般情况下函数调用参数,就按照函数定义时的参数顺序一个个传递,但是也可以通过指定函数参数名,并且不需要按照顺序向函数传递参数,实例如下:
object Test{
def main(args:Array[String]){
printInt(b = 5,a = 7);
printInt();
}
def printInt(a :Int = 5,b: Int = 7) = {
println("Value of a:" + a);
println("Value of b:" + b);
}
}
//其输出为
Value of a:7
Value of b:5
Value of a:5
Value of b:7
递归函数
即函数调用其本身
def fun(num:Int) :Int =
{
if(num ==1)
{
1;
}
else
{
num*fun(num-1);
}
}
偏应用函数
在某些情况下,方法中参数方法比较多,调用该方法非常频繁,每次调用均只有固定的一些参数变化,其他都不变,可以定义偏应用函数实现;
示例
import java.util.Date
object Test{
def main{args:Array[String]{
val date = new Date
val logShow = log(date,_:String)
logShow("aabb")
logShow("ccdd")
}
def log(date:Date,message:String) = {
println(date+":"+message)
}
}
匿名函数
匿名函数一般用在方法体中,不给命名,多用于方法的参数是函数时
定义匿名语法:
scala
参数列表 => 函数体
示例:
def add = new Function[Int,Int]{
def apply(x:Int):Int = x+1
}
//其匿名函数为:
var apply = (x:Int) => x+1
嵌套函数
嵌套函数就是在函数中定义函数
示例
def funInter(num:Int) = {
def funInter1(a:Int):Int = {
if(a == 1)
{
1
}
else
{
a*funInter(a - 1)
}
}
funInter1(num)
}
高阶函数
高阶函数就是操作其他函数的函数,只要返回的函数逻辑和参数中函数的逻辑一致即可,可以用匿名函数更改具体的实现内容;主要有三种:
1)方法的参数是函数
2)方法的返回是参数《必须显示的写出方法的返回值类型》
3)方法的参数和返回都是函数
// 示例1:方法的参数是函数
def fun1(a:Int = 10,b:Int = 20):Int = {
a + b
}
def fun2(f:(Int,Int)=>Int,s:String):String = {
val i:Int = f(100,200)
return i + "#" + s
}
// 示例2:方法的返回是函数
def fun5((i:Int):(String,String) => String ={
def fun6(s1:String,s2:String):String) = {
return s1 + "$" + s2 + "#" + s"$i"
}
return fun6
}
// 示例3:方法的参数和返回都是函数
def fun5(f:(Int,Int)=>Int):(String,String)=>String = {
def fun6(s1:String,s2:String):String = {
val i:Int = f(100,200)
return s1 + "$" +s2 + "#" + s"$i"
}
return fun6
}
// 高阶函数解释:
fun5(f:(Int,Int)=>Int):(String,String)=>String = { }
-- 类比 fun5(x:Int):String = { }
(f:(Int,Int)=>Int) - 类似于传入的参数格式,该处传入的是一个函数,函数具有两个Int输入,一个Int输出
(String,String)=>String - 类似于返回的参数,该处返回的一个函数,函数具有两个String输入,一个String输出
柯里化函数
柯里化函数实质上就是高阶函数的简化版,指的是将原来接受两个参数的函数变成新的接受一个参数的函数过程,新的函数返回一个以原有第二个参数为参数的函数
实例
def add(x:Int,y:Int) = x + y //调用add(1,2)
// 柯里化
def add(x:Int)(y:Int) = x + y //调用add(1)(2)
// 柯里化实现过程
// 前面说到柯里化函数实质上就是高阶函数的简化版
// add(1)(2)实质上是依次调用两个普通函数,第一次调用
使用一个参数x,返回一个函数类型的值,第二次使用参数y调用这个
函数类型的值,上述方法的实质是:
def add(x:Int) = (y:Int) => x + y
//即接受一个x为参数,返回一个匿名函数(y:Int) => x+y
//进一步接受y为参数,返回一个值x+y
闭包
Scala中闭包也是一种函数,返回值依赖于声明在函数外部的一个或多个变量,可以简单认为闭包是访问一个函数里面局部变量的另外一个函数
实例:
object Test{
def main{args:Array[String]){
println(Multi(1))
println(Multi(2))
}
var factor = 2
val multi = (i:Int) => i*factor;
}
//其中Multi引用的函数外面定义的变量factor,因此multi可以称为一个闭包