scala之函数

本文章将介绍scala函数的部分,并按照知识点讲解

知识点1:写scala函数,应该考虑的问题是重用性、可组合性(这两个特点,就像是UNIX高手会把多个单独用途的工具组合在一个复杂的管道命令里)、简短、可读(使用参数化函数可以是代码,更简短,更可读)

知识点2:纯函数(输入输出数据流全是显式(Explicit)的,通俗说就是函数体内的参数全部由函数提供),非纯函数反之;

//一些例子
//纯函数 相对来说比较稳定  但是实际中这种函数用比较少
def add(a:Int,b:Int) = a + b
//非纯函数 实际中用的比较多 但是开发时尽量少用(但是还是避免不了用,因为好多情况是纯函数解决不了的)
var a = 1
def addA(b:Int) = a + b

//矛和盾的问题

知识点3:我们知道函数如果没有参数可以不写”()”;

def hi="hi"
调用方法:hi //注意不能使用hi()
def hi()="hi"
调用方法可以:hi或者hi()

`函数的返回值也可写可不写,写上了话有更好的可读性,默认函数体嘴和一个表达式为返回值,但是需要在函数的表达式块结束前推出并返回值,可以使用return关键字

def aa(s:String):String={
    if(s==null) return null
    s.trim()
}

知识点4:使用表达式块调用函数(具有可读性)

def format(num:Int)=num.toString
调用时:format2)
可以写成:format(var b=2; 1+b*2)

知识点5:递归函数(重要),概念不多说,主要是优化(解决正常递归会创建多个栈,导致栈溢出,优化后不会创建新的栈,会使用前个函数的栈空间),主要是通过注解优化递归函数(@annotation.tailrec),优化条件是最后一个语句是递归调用的函数,否则,报错

//传统递归函数
def factorial(n: Int,x:Int): Int = {
  if( x >= 1 ) n * factorial(n,x-1)
  else 1
}
@annotation.tailrec
def factorialTailrec(n: BigInt, acc: BigInt): BigInt = {
    if(n <= 1) acc
    else factorialTailrec(n-1, acc * n)
}

知识点6:嵌套函数

//在某些情况,需要在一个方法中重复某个逻辑,但是把他作为外部方法又没有太大的意义,个人体检为局部函数,只能在函数体内使用
def max(a:Int,b:Int,c:Int)={
    def max(x:Int,y:Int)=if(x>y) x else y
    max(a,max(b,c))
}

知识点7:用命名参数调用函数,传统调用函数时,参数都是按照顺序,除了这种也可以指定函数参数的命名赋值,这样可以不用按照顺序

知识点8:有默认值的参数,就是为函数指定默认值,例如:def aa(c:String,b:String ="Jom") = s"$b$c"注意要把默认值的参数放在后面,否则在调用函数的时候,采用命名调用函数

*知识点9:**Vararg参数(通俗来讲就是当所定义的函数的参数不固定是,有一个或者多个采用

def sumitemsInt*):Int={
    var total = 0
    for (i <- items) tpta;+=1
    total
}

调用:sum(1,2)或者sum(1)或者...

知识点10:参数组,即把参数分解成参数组,列如:def max(x:Int,y:Int) = x+y 可变为 def max(x:Int) (y:Int)= x+y

知识点11:类型参数,即向函数传递类型参数(之前都是值参数);举例

//有个需求,定义一个函数的作用是输入什么类型,函数返回就是什么类型,
//如下为输入字符串类型,返回字符串类型 看起来很容易
def iden(s:String):String=s
//但是我们需要的是:函数输入什么类型,函数返回就是什么类型;如果需要Int、long、double、Boolean
//这样我们就需要每个类型都得写出,考虑我们可不可以给函数传入个类型参数,这样就可以根据传入的类型,返回什么的类型了
//如下
def identify[A](a:A):A=a
测试:val s:String = identity[String]("hello")  正确,其他类型也可以
由于scala可以进行类型推到,可以写成val s:String = identity("hello"),再简写点val s = identity("hello")

简写之后,并不是最可读的做法,因为读代码的人好需要检查函数的定义才能确定函数的返回值,但是这确实展示了scala类型系统的灵活性

知识点12:函数类型和值: 函数的类型是由输入类型和输出类型的一个简单的组合,有一个箭头从输入类型指向输出类型

def doub(x:Int):Int =x*2//此函数的类型为 Int=>Int
//定义一个函数的调用myDoub
val myDoub:Int=>Int=doub //个人理解为myDoub为函数的调用名,Int=>Int为函数调用名的类型(注意输入参数类型和输出参数类型一样时,不能写一个Int,也就是不能写成val myDoub:Int=doub),doub为函数调用的值(即调用什么函数)

myDoub在以后的讲解中被称为函数值
此外可以用通配符(_)为函数赋值

def doub(x:Int):Int =x*2
val myDoub =doub _//注意:doub和通配符(_)必须由空格分开

自我理解:在doub后面加上通配符,就代表着myDoub是函数调用而不是常量值
官方解释:这里不用myDoub显式函数类型来区分函数调用,下划线相当于一个占位符,表示简历的一个函数调用,这会返回一个函数值,我们可以把它保存到myDoub中
知识点总结:这里介绍了如何将函数处理为数据,可以把他们储存到值中,也可以赋为静态类型

知识点13:高阶函数:高阶函数也是函数,它包括一个函数类型的值作为输入参数和返回值(通俗来讲,就是一个函数输入参数是另一个函数或者一个函数的返回值是另一个函数)

def safe(s:String,f:String=>String)={//这里的参数f为函数类型为String=>String的函数
    if(s!=null) f(s) else s
}
def rever(s:String) = s.reverse

调用:safe("ready",rever)

知识点14:函数字面值(业界称呼比较多的是匿名函数):语法是(参数类型) => {函数体} 如:(name:String)=>s"hello,$name" 当然也可以去掉显示类型name=>s"hello,$name"
知识点总结:个人总结为正常函数是参数与函数体之间是用”=” 匿名函数是用”=>”

知识点15:占位符语法:就是匿名函数的一种缩写形式,即将命名参数替换为通配符(),给我的感觉就是本来匿名函数的语法的固定形式是知识点14讲的,但是现在给简写了,只剩下表达式,而表达式的参数由()表示,如(a:Int,b:Int)=>a+b可写为_+_
知识点总结:当我们在代码里看见由通配符(_)表示的表达式时,就可以断定这是个匿名函数

知识点16:部分应用函数
通常我们在调用函数时,需要指定所有的参数值,试想,当你想重复用这个函数,但是我只想改变其中一个函数的值,其他的值都一样,我们要怎么做呢?

def fact(x:Int,y:Int)=x+y
//正常调用
val f=fact _
val a= f(1,2)
//或者直接 val a = fact(1,2)

//实现上面的疑问
val f = fact(1,_:Int) //f 就是一个部分应用函数,注意通配符必须是显示类型的,也就是有:Int
val a = f(2) 得3
val b = f(3) 得4
val c = f(4) 得5

//此外还有个更简洁的方法
//在第一函数的时候使用柯里化
def fact(x:Int)(y:Int)=x+y
val f = fact(1) _
//调用
val a = f(1)

知识点17:传名参数。变现形式为(参数: => 参数类型);例如:def doub(x: =>Int)={x+2} 注意:和=>之间有空格 好处是此函数的参数可以接受值也可以接受函数(但是函数的返回值需是Int类型的)

def doub(x: =>Int)={x+2}

调用doub(doub(2)) 得6

知识点18:偏函数,试想当我们定义一个函数 函数体除数是0 函数就无法工作了(可以试下),相对于java来讲就是一个方法出现异常了,
通常避免错误的方法是在末尾使用通配符模式来捕获所有错误,但是这样一来,偏函数九个叫法就不合适了,你会发现偏函数在处理集合和模式匹配时更为有效,例如,可以手机一个集合中有给定偏函数接受的所有项

知识点19:用函数字面值调用高阶函数
这个就不做多余介绍了,有点累了,留住当绝招用(嘿嘿)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值