Scala函数及函数式编程
函数声明
函数相当于Java中的静态方法:除了递归之外不需要声明返回类型
- def as(x:Double)={if(x>=0) x else -x}
- def fac(n:Int):Int={if(n<=0) 1 else fac(n-1)}
注意:一,函数声明中并没有声明变量是否可变,函数的参数默认声明是不可变,也就是val。
二,不写没有返回值的方法必须用大括号括起来
简写
1.除了递归函数以外,函数的返回类型都不用写,这是因为递归函数的时候只有在运行的时候才能知道返回类型是什么,这显然是不行的,scala只能在代码编译的时候做类型推测。
2.当函数仅仅只有一条语句时不用加大括号
函数返回值
在scala中,语句块的最后一个值就是这个语句块的值,因此函数并不使用return来返回值,而是简单的把结果放到最后一条语句
函数使用简写
1.如果一个方法仅仅有一个参数,那么就可以不用点号和括号来引用,使用空格分割即可,注意这种方法仅仅适用于类实例方法,并不能在函数中使用
2.如果函数仅有一个参数,那么可以使用大括号来代替圆括号。如果使用柯里化,那么所有的函数都可以只有一个参数,这种情况下最后最后一个参数列表才可以这么做。
- def max(x:Any)(y:Any)=if(x>=y) x else y
- max(1){2}//2
特殊方法:
apply和update
apply:可以为一个类的伴生对象定义一个apply方法,相当于一个静态构造方法,定义在类的伴生对象中。可以让我们不加new来产生对象
- var c = Array[Int](10)
也可以给类定义一个对象方法apply
- var string = c(1)//可以看到把圆括号翻译成apply方法
update:可以为一个类定义一个update方法:f(arg1,arg2) = value,相当于f.update(arg1,arg2,value)
- var score = Map()
- score("Bob")=12
通用函数
map
map接受一个处理单个元素的函数,map把这个函数运用在列表的每个元素上放回一个一样长的列表
filter
filter接受一个返回boolean的的值,filter会取出得到true的元素,返回过滤过的列表
foreach
类似于map
mkString
相当于toString,但是需要一个分隔符
zip
zip把两个列表的元素依次结合得到一个元祖集合
reduce
reduceLeft接受一个接受两个参数的函数,reduceLeft会依次把前一次得到的结果和下一个列表元素传递给函数,最后得到一个单个元素
fold
foldLeft和foldRight接受一个需要两个参数的函数,并且依层调用如(1::2::3).foldLeft(1)(_*_)=6
以层次话的方式求值
一等公民
匿名函数
- increase = (x: Int) => {
- println("We")
- println("are")
- println("here!")
- x + 1
- }
- increase = (x: Int) => x + 9999
简写
注意简写只能用在向其他函数传递匿名函数时,由于简写利用的是自动推测,因此在其他情况下,编译器没有足够的信息来推测。
1.去掉类型声明
(x,y)=>x+y
2.当只有一个参数时可以去掉圆括号
x=>x+100
3.如果参数在表达式中仅仅出现一次,可以用下划线来表示,这时候就没必要再前面写明参数列表,因为编译器会把参数一次填入下划线的位置,注意有几个下划线就有几个参数
- list.reduce(_+_)//两个下划线表示有两个不同的参数
- list.forEach(print _)
事实上参数推测的能力更大
- def filesMatching(query: String,matcher: (String, String) => Boolean) = {
- for (file <filesHere;
- if matcher(file.getName, query))
- yield file
- }
- filesMatching(query, _.endsWith(_))
- filesMatching(query, _.contains(_))
- filesMatching(query, _.matches(_))
函数传递
- someNumbers.foreach((x: Int) => println(x))
赋值
- val a = sum _
- increase = (x: Int) => x + 9999
偏函数
- val b = sum(1, _: Int, 3)
- b(2)
- //对于类的偏函数
- val c = new Rational(1,_:Int)
- val vb = c(2)
- vb.toString
闭包
1.闭包会在每次外层函数调用的时候重新产生,就好像他们分别有两份一样,事实上可以在每次调用时把闭包函数所使用的变量绑定得到一个函数。
2.闭包语法:scala中不允许返回函数名,但是可以返回偏函数.
- def makeIncreaser(more: Int) ={
- def other(x:Int)=x+more
- val addMore = other _
- addMore
- }
或者返回匿名函数
- def makeIncreaser(more: Int) ={
- val addMore = (x:Int)=>{x+more}
- addMore
- }
可变参数
注意scala只允许最后一个参数可变
- def echo(args: String*) =for (arg <args) println(arg)
事实上args是一个Array,但是用这样的语法使得调用时,可以用多个参数调用
echo("hello", "world!")
但是不可以直接传递一个Array
尾递归
尾递归是指一个递归的递归语句出现在最后一个地方,注意不能有其他的语句,如下不可以。
- def boom(x: Int): Int =
- if (x == 0) throw new Exception("boom!")
- else boom(x-1)+ 1//最后的语句是一个加法
原理
尾递归在最后递归的地方并没有创建一个新的栈,而是跳转到函数的开头,因此可以大幅度的减小递归调用的开销。
高阶函数
可以接受函数或者返回函数的函数叫做高阶函数。
声明
- def filesMatching(query: String,matcher: (String, String) => Boolean) = {
- for (file <- filesHere;if matcher(file.getName, query)) yield file
- }
柯里化
把原来需要接受两个参数的函数变成两个接受一个参数的函数,新的函数接受一个参数并返回一个接受一个参数的函数
- def mul(x:Inr,y:Int)={x*y}
- def mul(x:Int)=(y:Int)=>x*y
(仅仅scala支持的简写)
- def mul(x:Int)(y:Int)={x*y}
实现控制结构
1.在只有一个参数的函数中可以用大括号代替圆括号,因此函数更像控制结构
2.控制结构简化后如下if(experssion*){experssion*},可以看做吧一个用两个参数的函数柯里化后的结果
- def withPrintWriter(file: File)(op: PrintWriter => Unit) {
- val writer = new PrintWriter(file)
- try {
- op(writer)
- } finally {
- writer.close()
- }
- }
- val file = new File("date.txt")
- withPrintWriter(file) {
- writer => writer.println(new java.util.Date)
- }
3.由于这种使用非常不方便,每次使用控制结构时都需要传递一个匿名函数,而且定义非常奇怪。因此scala引入了换名参数,在传统的控制结构中,后面的一部分可以看做一个无参有一个返回值的函数。声明如下:op:()=>Boolean,那么使用时就必须为()=>experssion。而换名参数把声明时的()换成了空格:op: =>Boolean,那么使用时就可以仅仅写expersion,这样就更加像传统的控制结构。同时,更重要的是,如果声明成函数。那么,由于声明和使用的地方不一致,也就不能在调用时使用本地变量。而换名参数正好克服了这种情况,因为他相当于在使用的地方声明,也就可以使用本地变量
loan pattern
在这种情况下,使用资源的函数不能控制资源,他只是声明需要一个资源,然后在产生资源的地方把资源借给他,使用之后,由产生资源的一方负责释放资源。因此资源从来没有赤裸裸地出现在程序中,保证了资源一定会得到释放。
- def withPrintWriter(file: File, op: PrintWriter => Unit) {
- val writer = new PrintWriter(file)
- try {
- op(writer)
- } finally {
- writer.close()
- }
- }
这儿的withPrintWrite把file资源借给op函数,op函数仅仅使用,没有管理资源的权限。
模式匹配和样例类
样例类
在类声明前面加上case关键字的叫做样例类
特性
1.每一个样例类都会有一个默认的apply方法
2.样例类中主构造器中的属性都会产生字段。
3.样例类添加了toString,hashcode和equal方法
4.样例类还实现了一个copy方法,用于产生一个新对象
val other = op.copy(operator="-",left=v,rigth=v)
模式匹配
- def simplifyTop(expr: Expr): Expr =
- expr match {
- case UnOp("",UnOp("",e)) => e // Double negation
- case BinOp("+", e, Number(0)) => e // Adding zero
- case BinOp("*", e, Number(1)) => e // Multiplying by one
- case _ => expr
- }
1.在这儿不仅仅有匹配还有变量的赋值,e就会在模式匹配的时候来得到变量的值
2.匹配还允许进行嵌套。
3._是通用匹配,其实就是这个结果一般都是无视或者抛出异常。
能力
常量匹配
- def describe(x: Any) =
- x match {
- case 5 => "five"
- case true => "truth"
- case "hello" => "hi!"
- case Nil => "the empty list"
- case _ => "something else"
- }
变量匹配
- expr match {
- case 0 => "zero"
- case somethingElse => "not zero: "+ somethingElse
- }
注意:
1.scala仅允许每个变量在匹配中被赋值一次
构造器匹配
- expr match {
- case BinOp("+", e, Number(0)) => println("a deep match")
- case _ =>
- }
这儿的类必须是样例类。
集合匹配
数组匹配
- arr match{
- case Array(0) => "0"
- case Array(x,y) => x+" "+y
- case Array(0,_*) => "0..."
- case _ => something else
- }
列表匹配
- lst match {
- case 0 :: Nil => "0"
- case x::y::Nil => x+" "+y
- case 0::tail => "0..."
- case _ => "something "
- }
元组匹配
- pair match{
- case (0,_) => "0 ..."
- case (y,0) => y + "0"
- case _ => "neither is 0"
- }
类型匹配
- def generalSize(x: Any) = x match {
- case s: String => s.length
- case m: Map[_, _] => m.size
- case _ => 1
- }
注意:
1.使用类型匹配可以同时实现类型检测和类型转化,因此在scala中要使用模式匹配来
2.由于java的类型擦除,故不能精确匹配泛型的类型
模式守卫
- // match only positive integers
- case n: Int if 0 < n => ...
- // match only strings starting with the letter ‘a’
- case s: String if s(0) == 'a' => ...
密封类
- sealed abstract class Expr
- case class Var(name: String) extends Expr
- case class Number(num: Double) extends Expr
- case class UnOp(operator: String, arg: Expr) extends Expr
- case class BinOp(operator: String,left: Expr, right: Expr) extends Expr
密封类仅允许同文件的类检测它,因此不用担心在模式匹配的时候出现未匹配的问题
Option类
其他用处
变量定义
- val exp = new BinOp("*", Number(5), Number(1))
- val BinOp(op, left, right) = exp
注意这儿的类必须是样例类
相关推荐
《Scala函数式编程》是针对希望学习FP并将它应用于日常编码中的程序员而写的,内容包括:函数式编程的概念;函数式编程相关的各种“为什么”和“怎么做”;如何编写多核程序;练习和检测。 从OOP到FP,思路的转化 ...
函数式编程(FP)是一种...《Scala函数式编程》是针对希望学习FP并将它应用于日常编码中的程序员而写的,内容包括:函数式编程的概念;函数式编程相关的各种“为什么”和“怎么做”;如何编写多核程序;练习和检测。
英文原版 scala函数式编程 function programming in scala
函数式编程语言或支持函数式特性的语言,如Haskell、Lisp、Scala、F#和JavaScript(通过ES6的箭头函数和闭包),提供了丰富的工具和概念来支持这一编程范式。例如,高阶函数(接受函数作为参数或返回函数的函数)...
Scala是一种多范式编程语言,它结合了面向对象编程和函数式编程的概念,设计目标是提供一种高效、简洁且可扩展的编程环境。本资源是一本高清版的Scala编程实战教程,适合对Scala有浓厚兴趣或者希望提升Scala技能的...
共13页第15讲-Scala编程详解:面向对象编程之Trait 共14页第16讲-Scala编程详解:函数式编程 共14页第17讲-Scala编程详解:函数式编程之集合操作 共9页第18讲-Scala编程详解:模式匹配 共11页第19讲-Scala编程详解:...
Scala,作为一种将面向对象编程和函数式编程完美结合的语言,提供了强大的函数式编程特性。Scala的函数式编程(FP)不仅包括高阶函数、匿名函数、递归和模式匹配等,还提供了不可变数据结构和纯函数等核心概念。本文...
共13页第15讲-Scala编程详解:面向对象编程之Trait 共14页第16讲-Scala编程详解:函数式编程 共14页第17讲-Scala编程详解:函数式编程之集合操作 共9页第18讲-Scala编程详解:模式匹配 共11页第19讲-Scala编程详解:...
标题“scala函数式编程-scalaz”所指的知识点涉及在Scala语言中使用Scalaz库来进行函数式编程。Scalaz是一个富类型库,它提供了许多扩展以增强Scala的函数式编程能力。它并不是Scala核心库的一部分,但为那些希望...
由于缺少具体内容,无法生成有关“Scala函数式编程”的详细知识点。如果您能提供具体的章节、段落或具有实际意义的内容,我将能够根据提供的信息撰写出符合要求的IT知识点。 然而,关于“Scala函数式编程”的话题,...
4. **函数式编程**:Scala鼓励使用不可变数据结构和高阶函数,函数是一等公民,可以赋值给变量,作为参数或返回值。λ表达式(匿名函数)和闭包也是重要的概念。 5. **类型推断**:Scala具有强大的类型推断能力,...
《Scala与Clojure函数式编程》这本书对那些希望从面向对象编程(OO)过渡到函数式编程(FP)的读者提供了极大的帮助。这本书被评价为入门者的安全绳索,帮助他们跨越面向对象和函数式编程两种截然不同的编程范式之间...
尽管JavaScript并不具备传统意义上强类型函数式编程语言的所有特性,但通过使用一些额外的类库,我们可以将JavaScript的函数式编程能力提高到与Scala或Haskell这类强类型函数式编程语言相同的水平。 函数式编程语言...
25 scala函数式编程.7z
Scala是一种静态类型的函数式编程语言,而Spark是一个分布式计算框架,尤其适合于大数据处理和分析。本教程将深入探讨这两者如何结合,实现高效的大数据分析、数据流处理以及机器学习任务。 首先,让我们来理解...
读书笔记:scala函数式编程练习