函数式编程
副作用
var x = 1
def xplusY_v1(y:Int) = x + y 无副作用
def xplusY_v2(y:Int) = {x += y;x} 有副作用,对x产生影响
引用透明
对于相同的输入,总是得到相同的输出
如果f(x)的参数x和函数体都是引用透明的,那么函数f是纯函数
append函数违反了引用透明
不变性
为了获得引用透明性,任何值都不能变化
val:immutable variable ----------- 常量
var:mutable variable -------------- 变量
lazy val:定义惰性求值常量。(应用场景:该变量有可能不会被用到,当该变量第一次使用,才会被求解)
可以不显示指定变量的类型,因为Scala会自动进行类型推导
scala>lazy val f = 20 * 30
f:Int = <lazy>
Unit 相当于java中的void,无返回值
scala>def foo() = throw new Exception("error occurred")
foo:()Nothing
scala>val name = "ChenFang"
name:String = ChenFang
scala>s"my name is ${name}"
res0:String = my name is ChenFang
代码块
{exp1;exp2}
{
exp1
exp2
}
函数
def functionName(param1:param1Type,param2:param2Type):ReturnType = {
//function body:expressions
}
object func_example{
def hello(name:String):String = {
s"Hello,${name}"
}
hello("ChenFang")
def add(x:Int,y:Int) = x + y
}
if表达式
if(logical_exp) valA else valB
if(true) 1 else 2 //>res0:Int = 1
if(false) 3 else 4 //>res1:Int = 4
val a = 1 //>a:Int = 1
if(a==1) a //>res2:AnyVal = 1
if(a!=1) "not one" //>res3:Any=()
if(a!=1) "not one" else a //>res4:Any = 1
object worksheet_chenfang{
val l = List("alice","bob","cathy")
for(
s<-l //遍历List集合
)println(s)
for{
s<-l
if(s.length>3) //filter
}println(s)
val result_for = for{
s<-l
s1 = s.toUpperCase()//variable binding
if(s1!="")
}yield(s1) //generate new collection
//result_for:List[String] = List(ALICE,BOB,CATHY)
}
try表达式try{
Integer.parseInt("dog")
}catch{
case_=>0 //下划线是通配符
}finally{
println("always be printed")
}
match 表达式exp match{//主要用在pattern match中
case p1 => val1
case p2 => val2
...
case _ => valn
}
code match{
case 1 => "one"
case 2 => "two"
case _ => "others"
}
"_"通配所有对象,相当于java里的default
求值策略
Scala里有两种求值策略(Evaluation Strategy)
Call By Value - 对函数实参(参数表达式)求值,且仅求值一次
Call By Name - 函数实参每次在函数体内被用到时都会求值
Scala通常使用Call By Value
如果函数形参类型以 => 开头,那么会使用Call By Name
def foo(x:Int) = x //call by value
def foo(x:=>Int) = x //call by name
scala>def bar(x:Int,y:=>Int) = 1
bar:(x:Int,y:=>Int)Int
scala>def loop():Int = loop
loop:()Int
scala>bar(1,loop)
res0:Int = 1
scala>bar(loop,1)
//因为需要先计算出loop,才能继续下一步。由于loop是死循环,所以该函数进入死循环
Scala语言支持1、把函数作为实参传递给另一个函数
2、把函数作为返回值
3、把函数赋值给变量
4、把函数存储在数据结构里
在Scala中,函数就像普通变量一样,可以应用到不同的地方,同样也具有函数的类型
在Scala中,函数类型的格式为A=>B,表示一个接受类型A的参数,并返回类型B的函数
例子:Int=>String是把整型映射为字符串的函数类型
高阶函数
用函数作为形参或返回值的函数,称为高阶函数
def operate(f:(Int,Int)=>Int)={
f(4,4)
}
def grreting() = (name:String)=>{"hello"+" "+name}
匿名函数匿名函数(Anonymous Function),就是函数常量,也称为函数文字量(Function Literal)
在Scala里,匿名函数的定义格式为
(形参列表)=>{函数体}
例子1: (x: Int) => x*x
例子2: (x: Int,y: Int) => x+y
例子3:
var add = (x: Int,y: Int)=> x+y //add是一个具有函数类型的变量
add(1,2) //返回值:Int=3
def greeting() = (name:String) => {s"Hello $name"}
greeting()("World")
def greeting(age: Int) = (name:String) => {s"Hello $name,your age is $age"}
greeting(23)("Flygar")
Scala柯里化(Curried Function)把具有多个参数的函数转换为一条函数链,每个节点上是单一参数
例如:以下两个add函数定义是等价的
def add(x:Int,y:Int) = x + y
def add(x:Int)(y:Int) = x + y //Scala里柯里化的语法
例子:
def curriedAdd(a:Int)(b:Int) = a + b
curriedAdd(2)(2) //4
val addOne = curriedAdd(1)_ //Int=>Int
addOne(2) //3
在函数式编程中,可以运用柯里化特性来构造新的函数,而不需要重新定义新函数。递归函数
递归函数在函数式编程中是实现循环的一种技术
例子:计算n!
def factorial(n:Int):Int =
if(n<=0) 1
else n*factorial(n-1)
尾递归函数尾递归函数中所有的递归形式的调用都出现在函数的末尾。
当编译器检测到一个函数调用是尾递归的时候,它就覆盖当前的活动记录而不是在栈中去创建一个新的。
@annotation.tailrec
def factorial(n:Int,m:Int):Int =
if(n<=0) m
else factorial(n-1,m*n)
factorial(5,1)
图截自慕课网视频:https://www.imooc.com/video/11275
scala.collection.immutable
集合有三大类:Set、Map、Seq
scala>val a = List(1,2,3,4)
a:List[Int] = List(1,2,3,4)
scala>val b = 0::a
b:List[Int] = List(0,1,2,3,4)
scala>val c = "x"::"y"::"z"::Nil //从后面开始连接
c:List[String] = List(x,y,z)
scala>"z"::Nil //Nil为空
res0:List[String] = List(z)
scala>"y"::res0
res1:List[String] = List(y,z)
scala>"x"::res1
res2:List[String] = List(x,y,z)
scala>val d = a:::c //连接两个集合
d:List[Any] = List(1,2,3,4,x,y,z)
访问集合内元素
scala>a.head
res3:Int = 1
scala>d.head
res4:Any = 1
scala>c.head
res5:String = x
scala>a.tail //返回除了第一个元素之外的元素列表
res6:List[Int] = List(2,3,4)
scala>c.tail
res7:List[String] = List(y,z)
scala>a.isEmpty
res8:Boolean = false
scala>Nil.isEmpty
res9:Boolean = true
scala>def walkthru(l:List[Int]):String = {
if(l.isEmpty) ""
else l.head.toString + " " + walkthru(l.tail)
}
walkthru:(l:List[Int])String
scala>walkthru(a)
res10:String = "1 2 3"
scala>a.filter(x => x%2==1) //filter会遍历列表,然后通过匿名函数筛选
res11:List[Int] = List(1,3)
scala>"99 Red Balloons".toList
res12:List[Char] = List(9,9, ,R,e,d, ,B,a,l,l,o,o,n,s)
scala>"99 Red Balloons".toList.filter(x => Character.isDigit(x))
res13:List[Char] = List(9,9)
scala>"99 Red Balloons".toList.takeWhile(x => x!='B')
res14:List[Char] = List(9,9, ,R,e,d, )
scala>c.map(x => x.toUpperCase)
res15:List[String] = List(X,Y,Z)
scala>c.map(_.toUpperCase)
res16:List[String] = List(X,Y,Z)
scala>a.filter(_%2 == 1)
res17:List[Int] = List(1,3)
scala>a.filter(_%2 == 1).map(_ + 10)
res18:List[Int] = List(11,13)
scala>val q = List(a,List(4,5,6))
q:List[List[Int]] = List(List(1,2,3),List(4,5,6))
scala>q.map(x=>x.filter(_%2==0))
res19:List[List[Int]] = List(List(2),List(4,6))
scala>q.map(_.filter(_%2==0))
res20:List[List[Int]] = List(List(2),List(4,6))
scala>q.flatMap(_.filter(_%2==0))
res22:List[Int] = List(2,4,6)
//reduceLeft(op:(T,T)=>T)
scala>a.reduceLeft((x,y)=>x+y)
res23:Int = 6
scala>a.reduceLeft( _ + _ )
res24:Int = 6
//foldLeft(Z:U)(op:(U,T)=>U)
scala>a.foldLeft(0)(_+_)
res25:Int = 6
scala>a.foldLeft(0)(_*_)
res26:Int = 6
//定义Range
scala>1 to 10 by 2
res37:scala.collection.immutable.Range = Range(1,3,5,7,9)
scala>(1 to 10).toList
res38:List[Int] = List(1,2,3,4,5,6,7,8,9,10)
scala>1 until 10
res39:scala.collection.immutable.Range = Range(1,2,3,4,5,6,7,8,9)
//Stream is a lazy List
scala>1#::2#::3#::Stream.empty
res40:scala.collection.immutable.Stream[Int] = Stream(1,?)
scala>val stream = (1 to 10000000).toStream
stream:scala.collection.immutable.Stream[Int] = Stream(1,?)
scala>stream.head
res41:Int = 1
scala>stream.tail //只对2求值
res42:scala.collection.immutable.Stream[Int] = Stream(2,?)
scala>(1,2)
res43:(Int,Int) = (1,2)
scala>1->2
res44:(Int,Int) = (1,2)
scala>(1,"Alice","Math",95.5)
res45:(Int,String,String,Double) = (1,Alice,Math,95.5)
scala>val t=(1,"Alice","Math",95.5)
t:(Int,String,String,Double) = (1,Alice,Math,95.5)
scala>t._1
res46:Int = 1
scala>t._2
res47:String = Alice
scala>def sumSq(in:List[Int]):(Int,Int,Int)=
| in.foldLeft((0,0,0))((t,v)=>(t._1+1,t._2 + v,t._3 + v*v))
sumSq:(in:List[Int])(Int,Int,Int)
scala>sumSq(a)
res50:(Int,Int,Int) = (3,6,14)
scala>val p = Map(1 -> "David",9 -> "Elwood")
p:scala.collection.immutable.Map[Int,String] = Map(1 -> David,9 -> Elwood)
scala>p(1)
res51:String = David
scala>p(9)
res52:String = Elwood
scala>p.contains(1)
res53:Boolean = true
scala>p.contains(2)
res54:Boolean = false
scala>p.keys
res55:Iterable[Int] = Set(1,9)
scala>p.values
res56:Iterable[String] = MapLike(David,Elwood)
scala>p + (8 -> "Archer")
res57:scala.collection.immutable.Map[Int,String] = Map(1 -> David,9 -> Elwood,8 -> Archer)
scala>p-1
res58:scala.collection.immutable.Map[Int,String] = Map(9 -> Elwood)
scala>p ++ List(2 -> "Alice",5 -> "Bob")//新生成一个MAP,所以下一条指令才会使得Map为空
res59:scala.collection.immutable.Map[Int,String] = Map(1->David,9->Elwood,2->Alice,5->Bob)
scala>p -- List(1,9,2)
res60:scala.collection.immutable.Map[Int,String] = Map()
scala实现快排
def qSort(a:List[Int]):List[Int] =
if (a.length<2) a
else
qSort(a.filter( _ <a.head)) ++
a.filter( _ == a.head) ++
qSort(a.filter( _ > a.head))
scala文档:http://docs.scala-lang.org/overviews/collections/introduction.html