前言
此系列为scala学习文章,适用于为学spark而学习scala
视频参考地址:Scala快速入门(适合为学Spark学习Scala的同学)
系列文章如下:
6. Scala学习06——trait特性、模式匹配、偏函数、样例类
资料下载地址:Scala课件资料.docx
目录
一、Scala方法的定义
- 方法定义语法 用def来定义
- 可以定义传入的参数,若有传入参数则需指定传入参数的类型
- 方法可以写返回值的类型也可以不写,若不写则会自动推断;有时候不能省略,必须写,比如在递归方法中或者方法的返回值是函数类型的时候。
- scala中方法有返回值时,可以写return,也可以不写return;当写return时,必须要写方法的返回值类型;若没写return,方法返回值类型可以省略,会自动推断类型,会把方法中最后一行当做结果返回
def max(a:Int,b:Int): Int={
if(a>b){
a
}else{
b
}
}
println(max(100,290))
- 如果返回值可以一行搞定,可以将{}省略不写
def min(a:Int,b:Int)= if(a<b) b else a
val res = min(100,22)
- 传递给方法的参数可以在方法中使用,并且scala规定方法的传过来的参数为val的,不是var的。
- 如果去掉方法体前面的等号,那么这个方法返回类型必定是Unit的。这种说法无论方法体里面什么逻辑都成立,scala可以把任意类型转换为Unit.假设,里面的逻辑最后返回了一个string,那么这个返回值会被转换成Unit,并且值会被丢弃。
def max(a:Int,b:Int){
if(a>b){
a
}else{
b
}
}
println(max(100,290))
输出结果为 ()
二、递归方法
- 递归方法要显式的声明函数的返回类型
def fun2(num :Int) :Int= {
if(num ==1)
num
else
num * fun2(num-1)
}
print(fun2(5))
三、参数有默认值的方法
- 默认值的函数中,如果传入的参数个数与函数定义相同,则传入的数值会覆盖默认值。
- 如果不想覆盖默认值,传入的参数个数小于定义的函数的参数,则需要指定参数名称。
def fun3(a :Int = 10,b:Int) = {
println(a+b)
}
fun3(b=2) // res =12
def fun2(a :Int = 10,b:Int=20) = {
println(a+b)
}
fun2() //30
fun2(100) //120
fun2(100,200) //300
四、可变长参数方法
- 在类型后 加 “*”,可将方法变为边长参数方法,传入多个参数
- 若指定传入参数类型,则传入参数只能为一种类型
- 若想要传入多个类型参数,则定义 elements :Any*
/**
* 可变参数个数的函数
* 注意:多个参数逗号分开
*/
def fun4(elements :Int*)={
var sum = 0;
for(elem <- elements){
sum += elem
}
sum
}
println(fun4(1,2,3,4))
五、匿名函数
- 函数与方法本质是一样的,只是在定义的时候稍微有些区别,多用于方法的参数是函数时
def fun4(arr:Int*) = {
for (elem <- arr){
println(elem)
}
//匿名函数
arr.foreach(elem => println(elem))
//匿名函数只用到一次
arr.foreach(println(_))
//匿名函数只有一个参数
arr.foreach(println)
}
println(fun4(1,2,3,4))
/**
* 匿名函数
* 1.有参数匿名函数
* 2.无参数匿名函数
* 3.有返回值的匿名函数
* 注意:
* 可以将匿名函数返回给定义的一个变量
*/
//有参数匿名函数
val value1: (Int)=>Unit = (a : Int) => {
println(a)
}
value1(1)
//无参数匿名函数
val value2 = ()=>{
println("我爱学习")
}
value2()
//有返回值的匿名函数
val value3 = (a:Int,b:Int) =>{
a+b
}
println(value3(4,4))
六、嵌套方法
/**
* 嵌套方法
* 例如:嵌套方法求5的阶乘
*/
def fun5(num:Int)={
def fun6(a:Int,b:Int):Int={
if(a == 1){
b
}else{
fun6(a-1,a*b)
}
}
// fun6定义了返回类型,fun5中最后一句返回自动识别返回类型为INT
fun6(num,1)
}
println(fun5(5))
七、偏应用函数
- 偏应用函数是一种表达式,不需要提供函数需要的所有参数,只需要提供部分,或不提供所需参数。
- 多用于 函数被调用频繁,每次调用只有固定的参数变化,其他的都不变,可以定义偏应用来实现
/**
* 偏应用函数
*/
def log(date :Date, s :String)= {
println("date is "+ date +",log is "+ s)
}
val date = new Date()
log(date ,"log1")
log(date ,"log2")
log(date ,"log3")
//想要调用log,以上变化的是第二个参数,可以用偏应用函数处理
val logWithDate = log(date,_:String)
logWithDate("log11")
logWithDate("log22")
logWithDate("log33")
八、高阶函数
函数的参数是函数,或者函数的返回类型是函数,或者函数的参数和函数的返回类型是函数的函数。
- 函数的参数是函数
//函数的参数是函数
def fun(a: Int, b: Int): Int = {
a + b
}
def fun1(f: (Int, Int) => Int, s: String) = {
val i: Int = f(100, 123)
i + "%%" + s
}
//写法1:单独定义一个函数,被调用
println(fun1(fun, "scala"))
//写法2:直接在参数里定义匿名函数
val res: String = fun1((a: Int, b: Int) => { a * b }, "hahahha")
println(res)
- 函数的返回是函数(要显式的写出函数的返回值类型,加 “_“ 就可以不用)
//函数的返回是参数 返回函数:(String,String)=>String
//写法一:显式写出返回类型
def dun(s:String):(String,String)=>String ={
def fun1(s1:String,s2:String):String={
s1 +"sssss"+s2 +"ccccc" +s
}
fun1
}
//写法二:加 _ 表示返回类型
def dun1(s:String)={
def fun1(s1:String,s2:String):String={
s1 +"sssss"+s2 +"ccccc" +s
}
//下划线 代表 强制将方法fun1直接变成 返回值类型
fun1 _
}
println(dun("dun")("a","b"))
- 函数的参数和函数的返回是函数
//函数的 参数和返回都是函数
//参数:(Int,Int)=>Int)
//返回:(String,String)=>String
def funfun(f:(Int,Int)=>Int):(String,String)=>String={
val i: Any = f(1, 2)
def funfun1(s1:String,s2:String):String={
s1+"###"+s2+"@@@"+i
}
funfun1
}
println( funfun( (a,b)=>{a+b} )("hello","world") )
九、柯里化函数
- 高阶函数中第二种(函数的返回是函数)的简化
- 柯里化(Currying)指的是把原来接受多个参数的函数变换成接受一个参数的函数过程,并且返回接受余下的参数且返回结果为一个新函数的技术
- scala柯里化风格的使用可以简化主函数的复杂度,提高主函数的自闭性,提高功能上的可扩张性、灵活性。可以编写出更加抽象,功能化和高效的函数式代码。
//柯理化
object KLH {
def main(args: Array[String]): Unit = {
def klh(x:Int)(y:Int) =x*y
val res=klh(3)(_)
println(res(4))
}
}
/**
* 柯里化函数
*/
def fun7(a :Int,b:Int)(c:Int,d:Int) = {
a+b+c+d
}
println(fun7(1,2)(3,4)) #10