零、匿名方法的简化逻辑
val ints = Array[Int](0, 2, 3, 4, 5)
ints.foreach(i=>{print(i)})
ints.foreach(i=>print(i))// 如果方法中只有一行语句,大括号可以省略
ints.foreach(print(_)) //如果参数只使用类一次,参数可以省略,使用_代替
ints.foreach(print)// 如果内部方法中只使用了一个参数,内部方法可以只写方法名
ints.foreach(i=>{
if(i>10){
print(i)
}else{
print(i+1)
}
})
ints.foreach(i=>if(i>10){print(i)}else{print(i+1)})// 由于只有一行,所以可以省区大括号
ints.foreach(i=>if(i>10){print(i)}else{print(i+1)})//由于i参数不止使用一次,所以不能使用_代替
一、方法的定义
def 方法名(带有类型的参数):返回值类型={
方法内容
}
注意点:
- 方法的定义使用def
- 可以定义传入的参数,要制定参数的类型
- 方法的返回值类型一般情况下可写可不写,不写的时候可以自动推断。但是在递归方法中或者方法的返回值是函数类型的时候不能省略,方法中使用return的时候不能省略,可以查看下方代码解释👇
- 方法有返回值的时候,可以写return,也可以不写。不写的时候会把方法的最后一行当作返回值;写了return,必须要写方法的返回值类型,可以查看下方代码解释👇
- 如果方法可以一行搞定,可以将{}省略 ,可以查看下方代码解释👇
- scala规定方法传过来的参数是val的,不是var;并且方法中的参数不能使用var和val再修饰
- 如果去掉方法体前边的等号,那么默认这个方法的返回值是Unit,上述3情况下也可以不用写返回值类型,因为只能是Unit返回值类型。并且注定了不会有返回值,即使你指定返回string类型的数据,也无法返回出去 可以查看下方代码解释👇
//代码解释上述注意点3:递归方法不写返回值类型会报错
def fun3(age:Int):Unit ={
val agex=age+1
if(age<10){
fun3(agex)
}else{
print(age)
}
}
//代码解释上述注意点4:带有return的时候,方法必须写明返回值类型
def fun1(name:String,sex:Int):String={
return "haha"
}
//代码解释上述注意点5
def fun1(name:String,sex:Int):String = return "haha"
def fun1(name:String,sex:Int):String= return "haha"
def fun2(name:String,sex:Int) = print(s"$name is haha")
//代码解释上述注意点7 方法体前边不使用=,就认定返回值为Unit类型,也就是无数据返回,即使使用了return,也无法返回数据
def fun4(name:String){
return "jaja"
}
二、方法与函数
其实方法就是函数,函数就是方法,非要区分的话,可以按照下边的说法
方法:类似于Java中对方法的认知,规规矩矩的按照规则写出的方法,生下来就是被调用执行的。
def fun1(name:String,sex:Int):String={
return "haha"
}
函数:可以被赋值给一个变量,也可以说就是匿名函数
//定义一个函数
val f1=(x:Int,y:String)=>{print(s"$x is y")}
//使用函数的变量调用函数
f1(1,"haha")
在函数式编程中,函数是最牛的,他可以像任何其他数据类型一样被传递和操作,函数也可以在方法中传递。 我自己阐述一遍:在函数式编程中,函数可以像一个数据(比如1,“abc”,3等等)一样被赋值给变量或者被传递给一个方法。
三、递归方法
递归方法如果有返回值,一定要写明返回值类型;如果没有返回值,也要写明返回值类型,除非连=一起不写。
def fun3(age:Int):Unit ={
val agex=age+1
if(age<10){
fun3(agex)
}else{
print(age)
}
}
四、参数有默认值的方法
如果有多个参数,含有默认值的参数在第一个,那么调用的时候又不想覆盖默认值参数,那么就需要指定参数名称。
def fun4(name:String="hahan",b:Int){
print(s"$b is name")
}
def fun5(name:String="hahan"){
print(s" is name")
}
def fun6(name:String="hahan",age:Int=6){
print(s" is name")
}
fun4("1",2) //第二个参数没有默认值
fun4(b=0) //不覆盖第一个参数,调用的时候需要指定第二个参数的名字
fun5()//不覆盖默认值
fun6(age=0) //只想覆盖第二个参数的默认值,调用的时候需要指定参数名称
五、可变参数的方法
在参数后边添加 * 号,说明该类型的参数可以写多个
def funSeq(s:String*)={
val s1: Seq[String] = s
s.foreach(e=>{print(e)})
//等同于
s.foreach(e=>print(e)) //如果方法体中只有一行代码,可以省略大括号
//等同于
s.foreach(print(_)) // 当匿名函数中只有一个参数的时候,并且这个参数只在一个地方用的时候,可以用下划线表示
//等同于
s.foreach(print)//当方法体中的方法中只用到一个参数的时候,下划线也可以省略
}
funSeq("a","b","c")
六、匿名函数
匿名函数可以作为一个方法的参数;匿名函数可以使用在方法的内部
三种写法
//第一种写法:后边的匿名函数赋值给了funn,类似于一种映射,匿名函数被映射给了funn函数变量
def funn:(Int,Int)=>Int=(a:Int,b:Int)=>{
a+b
}
funn(2,3)
//第二种写法:在方法中使用匿名方法
def funSeq(s:String*)={
val s1: Seq[String] = s
s.foreach(e=>{print(e)}) //匿名函数放到了foreach方法中当作参数使用
}
//第三种方式:把方法赋值给变量
val xxx:(String,Int)=>Int=(s:String,i:Int)=>{
0
}
(Int,Int)=>Int 这段代码就是一个匿名方法的类型,就像Int,String一样表示一个变量的类型,这里是方法的类型,(Int,Int)中表示匿名函数有两个参数,=>Int表示返回值是Int类型
(a:Int,b:String)=>{} 这段代码是匿名函数的实体,不是类型。(a:Int,b:String)匿名函数的两个参数名是a,b
=>是匿名函数的标志,这是匿名函数的固定写法
个人认为这些是函数式变成很重要的一个部分,也是函数式编程的一个代表特点
七、嵌套方法
嵌套方法是方法中定义方法
def tt3(s:String)={
def tt2(s1:String,x1:String)={
s1+";"+s+":"+x1
}
tt2("2","3")
}
八、偏应用函数
这里又有一个固定写法,偏应用函数未被固定写的那一个参数使用_下环线代替
def showLog(data:Date,log:String)={
print(s"$data is date,log is $log")
}
val date=new Date()
showLog(date,"a")
showLog(date,"b")
showLog(date,"c")
showLog(date,"d")
//上边的showlog方法被调用了四次,其中每次调用只是该表了第二个方法,这种情况下可以使用偏应用方法
def fun12=showLog(date,_:String)// 赋值的时候,第二个参数不做改动,就用_下划线代替,固定写法
fun12("a")
fun12("b")
fun12("c")
//这样调用fun的时候,date参数就默认有了,只需要改变第二个参数
九、高阶函数
1、方法的参数是方法
使用方法的参数传递方法,其实传递的是一段逻辑的名称,或者就是一段逻辑
//方法的参数是匿名函数,参数名是s1
def fun1(s1:(Int,Int)=>Int,a:Int):Int={
s1(a,0)
a
}
fun1(
(a:Int,b:Int)=>{a+b}, //传递进去一个匿名方法
0)
不同的写法
def add(a:Int,b:Int)={
a+b
}
def hi(fun:(Int,Int)=>Int,s:String): Unit ={
fun(100,200)+"*"+s
}
val unit: Unit = hi(add, "sd") //传进去一个方法,相当于传递了一段逻辑的名称,这个名称就叫add
2、方法的返回是方法
def fun2(a:Int):(Int,Int)=>String={ //方法类型作为返回值类型
val fun=(a:Int,b:Int)=>{
a+":"+b
}
fun //返回方法变量
}
注意事项:方法的返回是方法,必须显示的写出方法的返回值类型是方法,或者在返回的方法后边加上下划线
//a方法的返回值是方法,必须在a方法中表明返回值类型
def fun3(a:Int):(Int,Int)=>String={
def innerFun(a:Int,b:Int)={
a+":"+b
}
innerFun
}
//等同于
def fun4(a:Int)={//未写返回值类型,则必须在最后一行方法名后边添加 _
def innerFun(a:Int,b:Int):String={
a+":"+b
}
innerFun _ //方法名后边写_ ,表示将innerFun强制转换为方法类型。
}
//调用
fun4(2)(2,3)
如果只写fun4(2) ,那么只会执行fun4的内容,不会涉及到内部的innerFun方法内容
3、方法的参数和参数是方法
前两种的结合
def fun5(a:Int,fun1:(String,String)=>Int):(Int,Int)=>String={
def innerFun(a:Int,b:Int):String={
// val c=fun1("2","33") //将犯法的返回值赋值给变量
val c=fun1 //将方法参数赋值给一个变量
val sc=c("2","3")//通过变量调用方法
println(s"$sc")
a+":"+b+c
}
innerFun
}
fun5(0,(s:String,l:String)=>{
s.length+l.length
})(0,0)
//也可以省去匿名方法体参数的类型,类型推断可以推断出来参数类型
fun5(0,(a,b)=>{
a.length+b.length
})
十、柯里化函数
方法的返回值是方法的另外一种调用方式
def kelihua(a:Int,b:Int)(c:Int,d:Int)={
a+b+c+d
}
kelihua(2,2)(3,4)
// 上述就是柯里化函数的写法,是方法的返回值是方法的另外一种写法
十一、闭包
闭包是一个函数,返回值依赖于声明在外部的一个或多个变量 简单来说就是可以访问不在当前作用于范围内的一个函数
def main(args:Array[String]):Unit={
val a=100 //变量a不处于其有效作用于时,函数还能够对变量进行访问
fun5(0,(s:String,l:String)=>{
s.length+l.length+a //a不在方法中,还可以被访问,a是一个自由变量
})(1,2)
}