方法、函数、高阶函数
1、方法
def method1(x:Int,y:Int):Int={x+y}
def 方法名(变量名:变量类型,...):返回值类型={方法体}
scala方法可以定义在方法中
方法如果定义在类中是可以重载的
方法如果定义在方法中是不可以重载的
2、方法简化原则
1)方法体只有一行,{}可以省略
2)返回值类型为Unit,=可以省略
3)方法体的最后一行作为返回值类型,则返回值类型可以省略
4)方法不需要参数,()可以省略
注意:
1和2,不能同时省略
方法体中有return关键字,则3不能省略
4如果省略了,调用时也要省略()
4如果没有省略,调用时()可省可不省
3、方法参数
java方法参数:
1、public 返回值类型 方法名(类型 参数名,..) { 方法体 }
2、可变参数: public 返回值类型 方法名(类型... 参数名) { 方法体 }
scala方法的参数
1、正常形式: def 方法名(参数名:类型,..):返回值类型 = {方法体}
2、默认值: def 方法名(参数名:类型=默认值,..):返回值类型 = {方法体}
如果默认值单独使用,在定义方法的时候需要将默认值定义在参数列表最后面
3、带名参数:
指调用方法的时候将指定值传递给哪个参数: 方法名(参数名=值)
4、可变参数: def 方法名(参数名:参数类型,..,参数名:参数类型*)
可变参数必须定义在参数列表的最后面
可变参数不能与默认值参数、带名参数一起使用
可变参数不能直接传递集合,但是可以通过 集合名称:_* 的方式将集合的所有元素传递给可变参数
def main( args: Array[ String ] ) : Unit = {
val value = getDates( 7 , "/com/hive/user/warehouse/user_info" )
println( getPaths( value: _* ) )
}
def getPaths( paths: String * ) : Unit = {
println( paths. toBuffer)
}
def getDates( n: Int , prefix: String ) = {
val time = LocalDateTime. now( )
for ( i <- 1 to n) yield {
val time1 = time. plusDays( - i)
val str = time1. format( DateTimeFormatter. ofPattern( "yyyyMMdd" ) )
s"$prefix/$str"
}
}
4、函数
定义方式:val或var 变量名 = (变量名:变量类型,...)=>{方法体}
函数的返回值就是函数体的块表达式的结果值
函数不可以重载,因为函数名其实就是变量名,同一作用域不能存在同名参数
def main( args: Array[ String ] ) : Unit = {
var f1 = ( x: Int , y: Int ) => {
x + y
}
println( f1)
println( f1( 1 , 2 ) )
println( f2( 3 ) )
println( f3)
println( f3( 1 , 3 ) )
}
var f2 = ( x: Int ) => x* 10
val f3 = new Function2[ Int , Int , Int ] {
override def apply( v1: Int , v2: Int ) : Int = {
v1+ v2
}
override def toString( ) : String = "this is f3"
}
5、函数简化
如果函数体中只有一行语句,{}可以省略
函数在调用的时候必须带上()
6、方法和函数的关联
方法可以看成是函数,函数也是对象
区别:
1)方法可以重载,函数因为其实是对象,所以在同个作用域下不能重载
2)方法在方法区,函数在堆区
联系:
1)方法可以转为函数: val或var 函数名=方法名 _
2)如果方法定义在方法内,那它其实就是函数
def main( args: Array[ String ] ) : Unit = {
var f1 = add _
add2( 1 , add)
}
def add( x: Int ) = {
x * 10
}
def add2( x: Int , func: Int => Int ) = {
func( x)
}
7、高阶函数
高阶函数: 以函数作为参数或者返回值的方法/函数称之为高阶函数
匿名函数:没有名字的函数,不能单独使用,只能作为参数写在调用高阶函数的参数列表内(在简化中有示例)
在方法的参数列表中定义函数,相当于在参数列表中有一个参数的类型是函数(因为函数也是对象)
def 方法名(变量名:变量类型,..变量名:函数定义类型):返回值类型={方法体}
8、高阶函数简化
调用高阶函数时:
1、函数的可以直接写在方法参数列表里,相当于匿名函数
2、函数的参数类型可以省略
3、如果函数的参数在函数体中只使用了一次,可以用_代替
注意1:多个参数的参数列表顺序和函数体内调用的顺序必须一样才可以简化
2:单个参数并且在函数体中直接返回时,也不能简化
3:参数在函数体中用()中使用,并且()内构成一个表达式时,也不能简化
4、如果函数的参数只有一个,()可以省略
def main( args: Array[ String ] ) : Unit = {
val func = ( x: Int , y: Int ) => x + y
println( add( 1 , 2 , func) )
println( add( 1 , 2 , ( x: Int , y: Int ) => x + y) )
println( add( 1 , 2 , ( x, y) => x + y) )
println( add( 1 , 2 , _ + _) )
println( add2( 1 , x => x + 1 ) )
}
def add( x: Int , y: Int , func: ( Int , Int ) => Int ) = {
func( x, y)
}
def add2( x: Int , func: Int => Int ) = {
func( x)
}
9、函数柯里化和闭包
1.柯里化:将一个参数列表内有多个个参数的函数转化成接受多个单参数列表的过程
2.闭包:就是一个函数/方法和与其相关的引用环境(变量)组合的一个整体
println( add( 1 , 2 , 3 ) )
println( add2( 1 ) ( 2 , 3 ) )
println( add3( 1 ) ( 2 ) ( 3 ) )
val i = 3
def b( x: Int ) = {
x + i
}
}
def add( x: Int , y: Int , z: Int ) : Int = {
x + y + z
}
def add2( x: Int ) : ( Int , Int ) => Int = {
( y: Int , z: Int ) => {
x + y + z
}
}
def add3( x: Int ) : Int => Int => Int = {
( y: Int ) => {
( z: Int ) => {
x + y + z
}
}
}
10、递归
与java的一样,必须要有跳出递归的判断条件
另外注意,递归的方法必须写返回值类型
11、惰性求值
加上关键字lazy后,该变量会在使用时才赋值,注意不能修饰var变量
12、控制抽象
{}包裹的代码块,可以赋值给变量,也可以用来作为参数传给方法,此时这个{}就是控制抽象
def 方法名(参数名:参数类型,...变量名: => 块表达式返回值类型) :返回值类型={方法体}
其中[: =>块表达式返回值类型]就是控制抽象,后续调用时直接写变量名,不能写()
def main( args: Array[ String ] ) : Unit = {
f1( {
println( "test f1" )
} )
loop( 5 ) ( {
println( "test loop" )
} )
}
def f1( op: => Unit ) = {
op
op
op
}
def loop( x: Int ) ( op: => Unit ) : Unit = {
if ( x > 0 ) {
op
loop( x - 1 ) ( op)
}
}