scala高级函数
🔥函数对于scala(函数式编程语言)来说非常重要,大家一定要学明白,加油!!!!🔥
1.return可以省略,Scala会把函数体最后一行代码作为返回值
def f0(name:String):String ={
name
}
println(f0("scala"))
2.如果函数体内只有一行代码,可以省略花括号
def f2(name:String):String=name
3.如果返回值类型如果能推断出来,:和返回值类型可以一起省略
def f3(name:String)=name
这不就相当于数学上的函数嘛! f(x)=x。 这也是至简原则的目的,让函数最终尽可能符合我们数学上的使用习惯。
4.如果return没有省略,则返回值类型不能省略
def f4(name:String)={
return name
}
//会报错
5.如果函数声明Unit(空类型),那么即使函数体中使用return也不起作用
def f5(name:String):Unit={
return name
}
6.scala如果期望是无返回值类型,可以省略等号,这种函数也叫做过程,不存在映射关系
def f6(name:String){
println(name)
}
7.如果函数无参数,但是声明了参数列表,那么调用时,小括号,可加可不加
def f7():Unit={
println(name)
}
f7()
f7
8.如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略
def f8:Unit={
println(name)
}
f8
9.如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略,也不需要返回值。也就是匿名函数!lambda表达式
(name:String) =>{println(name)}
lambda表达式没有函数名如何调用呢?
用法1:直接定义个变量,这样就相当于有了名字
val fun =(name:String) =>{println(name)} //lambda表达式的返回值(函数类型)赋给fun 相当于有了名字
fun("scala")
用法2:定义一个函数,以函数作为参数传入
//相当于函数的参数是固定的,这个函数的操作却决于传入的函数
val fun =(name:String) =>{println(name)}
def f(func:String =>Unit):Unit={ //String =>Unit 是函数的类型,代表函数的参数是String类型,返回类型是Unit
func("scala")
}
f(fun)
f((name:String) =>{println(name)})
匿名函数就是一个表达式,它的返回值也就是这个表达式的值。
1.参数类型可以省略,会根据形参进行自动推导
f((name) =>{println(name)}) //看用法2中定义的函数,传入的参数已经定义死了,必须是String =>Unit(String类型)
2.类型省略之后,如果只有一个参数,圆括号可以省略.
f(name=>{println(name)})
3.匿名函数如果只有一行,大括号也可以省略
f(name=>println(name))
4.如果参数只出现一次,则参数省略且后面可以用_代替,注意对应顺序
f(println(_))
5.如果可以推断出,当前传入的println是一个函数体,而不是调用语句,可以直接省略下划线
f(println) //传入的是一个操作
案例:定义一个“二元运算”函数,只对1和2两个数操作,但是具体的运算通过传入的参数决定
def dualFunction(fun:(Int,Int)=>Int):Int={
fun(1,2) //具体的参数已经是定死的
}
val add = (a:Int,b:Int)=>a+b
val minus = (a:Int,b:Int)=>a-b
println(dualFunction(add))
println(dualFunction(minus))
println(dualFunction((a,b)=>a-b))
println(dualFunction(_-_))
函数在scala编程里面是一等公民,不想Java只能在类里面定义方法,非常灵活,在一个代码块中就可以定义函数,调用函数。
1.函数可以作为值进行传递,类似给函数起别名
def f(n:Int):Int={
println("f调用")
n+1
}
val f1 = f _ //f _ 代表f这整个函数体
val f2:Int=>Int =f //这样f1(函数对象)就是函数类型(f2:Int=>Int),编译器知道要传函数,所以可以只写个f
2.函数作为参数进行传递
这里就是匿名函数案例演示的那种,参数是定义死的,具体操作看传入的函数(参数)
但是数据一定要定义死嘛?我们可以函数参数和数据参数一起传入
def dualEval(op:(Int,Int)=>Int,a:Int,b:Int):Int={
op(a,b)
}
def add(a:Int,b:Int):Int={
a+b
}
println(dualEval(add,12,35)) //把普通函数作为参数
3.函数作为函数的返回值返回
看到这里我们可以发现,只要是值用到的地方,我们都可以用函数进行代替。
这里就设计到函数嵌套了
def f5():Int => Unit{ //Int => Unit这里说明返回值是函数类型
def f6(a:Int)={
println("f6调用"+6)
}
f6 //return 可以省略
}
println(f5()) //这里得到的是一个引用(函数),也就是得到的f6()
println(f5()(25))
**应用案例:**对数组进行处理,将操作抽象出来,处理完毕之后的结果返回一个新的数组。(也就是大数据map操作)
yield:就是在for循环中,每次循环都会产生一个值,然后将每次产生的值保存,最后组成一个集合。
val arr:Array[Int]=Array(12,45,75,98) //每次只对数组中的一个元素进行操作,这个操作是单独抽象的,只需要单独的定义操作
def arrayOperations(array: Array[Int],op:Int=>Int):Array[Int]={
for (elem <- array) yield op(elem)
}
//定义一个加1操作
def addOne(elem:Int):Int={
elem+1
}
//调用函数
var newArray:Array[Int]=arrayOperations(arr,addOne)
println(newArray.mkString(","))
//这里传入匿名函数也是可以的
var newArray2 = arrayOperations(arr,_+1 )
这里的应用是以后处理大数据,来了一堆集合,数据就是那些,但是需要进行很多步操作, 我们通过这样可以单独定义他 们的操作。
案例:通过函数嵌套的方式接受三个参数,当这三种类型参数都为假时,返回fales。
def f1(i:Int):String=>(Char=>Boolean)={
def f2(s:String):Char=>Boolean={
def f3(c:Char):Boolean={
if (i==0&&s==""&&c=='0') false else true
}
f3
}
f2
}
println(f1(0)("")('0')) //结果为false
//可以用匿名函数进行简化书写,但是这种书写也会被函数的柯里化给代替
def func1(i:Int):String=>(Char=>Boolean)={
s=>c=> if (i==0&&s==""&&c=='0') false else true
}
闭包:如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的环境成为闭包
函数柯里化:把一个参数列表的多个参数,变成多个参数列表,每个参数都是一个小括号
函数性编程语言(scala)定是支持闭包的。它可以延长他所使用的参数的做作用域(如上面那个案例,内层函数用到了外层函数的一个局部变量或者是一个参数,为了我们在调用的时候还能分层调用,在调用的时候第二步还能使用外层函数的参数,那么闭包会把外层函数的参数或者局部变量和内层函数打包起来,保存到一个函数对象里面,存放在堆内存里面)。
柯里化:
def addCurrying(a:Int)(b:Int):Int={
a+b
} //一旦使用了柯里化,底层一定使用了闭包
println(addCurrying(23)(32))
}
递归:一个函数/方法在函数/方法体内又调用了本身
方法调用自身
方法必须要有跳出的逻辑
方法调用自身时,传递的参数应该有规律
Scala中递归必须声明返回值类型
//递归计算阶乘
def fact(n:Int):Int={
if (n==0) return 1 //这个return不能省,因为scala只能自动返回最后一行,这里不是最后一行
fact(n-1)*n
}
//尾递归:递归最后一行返回的只有对于自身的调用,没有其他额外的计算,这样当前这层函数不用保存任何东西,这样就用压栈了,节省空间。
def tailFact(n:Int):Int={
@tailrec //如果写的不是尾递归,idea会报错
def loop(n:Int,currRes:Int):Int={
if(n==0)return currRes
loop(n-1,currRes*n) //每次调用我不需要保存上一层的任何信息,不用压栈,做一个栈帧的覆盖就节省空间了。
}
loop(n,1)
}
//尾递归只有函数式编程语言才支持,比如Java就不支持
1.值调用:把计算后的值传递过去
2.名调用:把代码传递过去
//传值参数
def f0(a:Int):Unit={
println("a"+a)
}
def f1():Int={
println("f1调用")
12
}
f0(f1)
//传名参数,传递的不再是具体的值,而是代码块
def f2(a:=>Int):Unit={ //注意这里参数的类型
println("a:"+a)
println("a:"+a)
}
f2(f1()) //每一次用到a的时候,都会把f2中完整的代码块执行一遍。
传名调用的案例:自己实现一个while循环函数
//1.用闭包实现一个函数,将代码块作为参数传入,递归调用
def myWhile(condition:=>Boolean):(=>Unit)=>Unit={
//内层函数需要递归调用,参数就是循环体(代码块)
def doLoop(op:=>Unit):Unit={
if(condition){
op
myWhile(condition)(op) //尾递归
}
}
doLoop _
}
n=10
myWhile(n>=1){
println(n)
n-=1
}//参数是一个代码块时,小括号可以省略
//2.用匿名函数实现
def myWhile2(condition:=>Boolean):(=>Unit)=>Unit={
//内层函数需要递归调用,参数就是循环体(代码块)
op=>{
if(condition){
op
myWhile2(condition)(op) //尾递归
}
}
}
//3.用函数柯里化实现
def myWhile(condition:=>Boolean)(op:=>Unit):Unit={
if(condition){
op
myWhile3(condition)(op)
}
}
说明:函数的返回值被声明lazy时,函数的执行将被推迟,直到我们首次对此取值,该函数才会被执行,这种函数我们称之为惰性函数。
(不用到,不执行加载)
lazy val result:Int = sum(13,47)
println("1.函数调用")
println("2.result="+result)
def sum(a:Int,b:Int):Int={
printlb("3.sum调用")
}
//最后输出顺序时1 3 2
我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re
我正在尝试用ruby中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了
我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin
我有一个涉及多台机器、消息队列和事务的问题。因此,例如用户点击网页,点击将消息发送到另一台机器,该机器将付款添加到用户的帐户。每秒可能有数千次点击。事务的所有方面都应该是容错的。我以前从未遇到过这样的事情,但一些阅读表明这是一个众所周知的问题。所以我的问题。我假设安全的方法是使用两阶段提交,但协议(protocol)是阻塞的,所以我不会获得所需的性能,我是否正确?我通常写Ruby,但似乎Redis之类的数据库和Rescue、RabbitMQ等消息队列系统对我的帮助不大——即使我实现某种两阶段提交,如果Redis崩溃,数据也会丢失,因为它本质上只是内存。所有这些让我开始关注erlang和
如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只
说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时
我需要一个通过输入字符串进行计算的方法,像这样function="(a/b)*100"a=25b=50function.something>>50有什么方法吗? 最佳答案 您可以使用instance_eval:function="(a/b)*100"a=25.0b=50instance_evalfunction#=>50.0请注意,使用eval本质上是不安全的,尤其是当您使用外部输入时,因为它可能包含注入(inject)的恶意代码。另请注意,a设置为25.0而不是25,因为如果它是整数a/b将导致0(整数)。
我需要从json记录中获取一些值并像下面这样提取curr_json_doc['title']['genre'].map{|s|s['name']}.join(',')但对于某些记录,curr_json_doc['title']['genre']可以为空。所以我想对map和join()使用try函数。我试过如下curr_json_doc['title']['genre'].try(:map,{|s|s['name']}).try(:join,(','))但是没用。 最佳答案 你没有正确传递block。block被传递给参数括号外的方法
在这段Ruby代码中:ModuleMClassC当我尝试运行时出现“'M:Module'的未定义方法'helper'”错误c=M::C.new("world")c.work但直接从另一个类调用M::helper("world")工作正常。类不能调用在定义它们的同一模块中定义的模块函数吗?除了将类移出模块外,还有其他解决方法吗? 最佳答案 为了调用M::helper,你需要将它定义为defself.helper;结束为了进行比较,请查看以下修改后的代码段中的helper和helper2moduleMclassC
有没有办法快速将表格格式的ruby哈希打印到文件中?如:keyAkeyBkeyC...1232343451253474456...其中散列的值是不同大小的数组。还是使用双循环是唯一的方法?谢谢 最佳答案 试试我写的这个gem(在表中打印散列、ruby对象、ActiveRecord对象):http://github.com/arches/table_print 关于ruby-如何以表格格式快速打印Ruby哈希值?,我们在StackOverflow上找到一个类似的问题: