纯函数来编写程序。
var x = 1
def XplusY_V1(y:Int) = x + y
def XplusY_V2(y:Int) = {x += y;x}
上面第一个函数是输入一个int类型的y,第二个函数是输入一个int类型的y返回值是x。
第二个函数相对于第一个函数对变量x产生了副作用。改变了x的值。
* 引用透明(Referential Transparency)对于相同的输入,总能得到相同的输出。
如果f(x)的参数x和函数体都是引用透明的,那么函数f是纯函数。
违反引用透明
函数是一等公民(First-class Function)一切都是计算,函数式编程中只有表达式,变量、函数都是表达式。
函数也可以作为参数或者返回值。
表达式求值策略:严格求值和非严格求职。
Call By Value属于严格求值
Call By Name属于非严格求职
下载JDK最新版本,将环境变量添加到配置文件中
从http://www.scala-lang.org/download上下载了Scala的最新版本,将环境变量添加到配置文件中就可以用了。
REPL(Read Evaluate Print Loop)就是scala命令行的运行环境。
在linux命令行输入scala就可以直接进入到scala REPL中。
devil@devilshome:~$ scala
Welcome to Scala 2.12.0-M4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_60).
Type in expressions for evaluation. Or try :help.
scala> println("Hello World")
Hello World
scala>
println()函数在所有Scala代码中都可用。
scala> val x =1
x: Int = 1
scala> var x = 1
x: Int = 1
scala>
var 和 val 的区别稍后解释。
在http://scala-ide.org/download/sdk.html下载专为scala的eclipse
- new一个Scala Project
- new 一个Scala Worksheet
worksheet是可以在IDE中直接进行代码的运行和结果的获得,是交互式的。
默认直接生成一个Object
object worksheet {
println("Welcome to the Scala worksheet") //> Welcome to the Scala worksheet
val x = 1 //> x : Int = 1
println(x) //> 1
}
输入代码以后保存,会直接把输出的结果打印在右边。
新建一个package demo01
在package中新建一个scala app
package demo01
object Greeting extends App {
println("Hello,"+args(0)+"!")
}
运行时设置main class和参数,main class的格式为包名.类名。
在控制台查看打印输出的结果
Hello,Devil!
在文件夹中新建一个.scala文件,如Greeting.scala
在命令行中键入
devil@devilshome:~/example$ scalac Greeting.scala
编译完成后,原文夹下多了一个Greeting.class文件,这个就是编译后的字节码文件。
再对这个字节码文件进行使用。
devil@devilshome:~/example$ scala Greeting Jack
Hello,Jack!
devil@devilshome:~/example$ scala Greeting Devil
Hello,Devil!
scala> val x=10
x: Int = 10
scala> val y :Int =20
y: Int = 20
scala> x+x
res0: Int = 20
scala> res0
res1: Int = 20
scala> res0*res1
res2: Int = 400
scala> z=200
:16: error: reassignment to val
z=200
^
//val的值不能被修改
scala>
scala> val d = 20
d: Int = 20
scala> val e = 30
e: Int = 30
scala> lazy val f = d * e
f: Int = <lazy>
scala> f * 10
res3: Int = 6000
scala> f
res4: Int = 600
scala>
精度问题
scala> val b :Byte = 10
b: Byte = 10
scala> val x :Long = 10
x: Long = 10
scala> val y :Long = b
y: Long = 10
scala> val z : Byte = x
:12: error: type mismatch;
found : Long
required: Byte
val z : Byte = x
^
scala>
scala> val q = 'X'
q: Char = X
Scala中的Unit类型类似于java中的void。主要的不同是在Scala中可以有一个Unit类型值,也就是(),然而java中是没有void类型的值的。除了这一点,Unit和void是等效的。一般来说每一个返回void的java方法对应一个返回Unit的Scala方法。
scala> val u : Unit=()
u: Unit = ()
scala> val p = ()
p: Unit = ()
scala> def foo() = throw new Exception("error occurred")
foo: ()Nothing
scala> val name = "devil"
name: String = devil
scala> s"my name if ${name}"
res5: String = my name if devil
object func_wxamples {
def hello(name: String): String = {
s"hello,${name}"
} //> hello: (name: String)String
hello("devil") //> res0: String = hello,devil
def hello2(name: String) = {
s"hello,${name}"
} //> hello2: (name: String)String
hello2("devil") //> res1: String = hello,devil
def add (x:Int,y:Int) = x+y //> add: (x: Int, y: Int)Int
add(5,3) //> res2: Int = 8
}
在scala中,if是表达式,而不是语句。
object fun_if_example {
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) "不是1" //> res3: Any = ()
if (a != 1) "不是1" else a //> res4: Any = 1
}
object fun_for_examples {
val l = List("elisa", "sin", "satoshi") //> l : List[String] = List(elisa, sin, satoshi)
for (
s <- l //用s循环遍历l中的元素
) println(s) //> elisa
//| sin
//| satoshi
for (
s <- l if (s.length > 3)
) println(s) //> elisa
//| satoshi
val result_for = for {
s <- l
s1 = s.toUpperCase()
if (s1 != "")
} yield (s1) //> result_for : List[String] = List(ELISA, SIN, SATOSHI)
}
yield (s1)的意思是将s放入一个新的collection中。
try{}
catch{}
finally{}//无论有没有发生异常,我们都会执行finally这个代码块
exp match{
case p1 => val1
case p2 => val2
…
case _ => valn
}
object func_match_example {
val code = 3 //> code : Int = 3
val result_match = code match{
case 1 => "one"
case 2 => "two"
case _ => "three"
} //> result_match : String = three
}
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)
res6: Int = 1
scala> bar(loop,1)
第二个bar(loop,1)在进行死循环,因为x是Call By Value的需要对所有表达式求值才能进行下一步运算。
scala中函数是第一等公民
Scala语言支持:
1. 把函数作为实参传递给另外一个函数
2. 把函数作为返回值
3. 把函数赋值给变量
4. 把函数存储在数据结构中
在scala中,函数就像普通变量一样,同样也具有函数类型。
高阶函数
用函数作为形参或返回值的函数,成为高阶函数
匿名函数
就是函数常量,也成为函数文字量。
在scala里,匿名函数的定一个是为(形参列表)=>{函数体}
柯里化函数把具有多个参数的函数转换为一条函数链,每个节点上是单一参数。
eg:下面两个函数的定义是等价的
def add(x: Int,y: Int) = x+y
def add(x: Int)(y: Int) = x+y
递归函数在函数式变成中是实现循环的一种技术。
def factorial(n: Int): Int =
if (n<=0) 1
else n* factorial(n-1)
尾递归
尾递归函数中所有递归形式的调用都出现在函数的末尾。
当编译器检测到一个函数调用是尾递归的时候,它就覆盖当前的活动记录而不是在栈中去创建一个新的。
避免堆栈溢出
@annotation.tailrec //告诉scala编译器,对这个递归进行尾递归优化
def factorial(n: Int,m: Int): Int =
if (n<=0) m
else factorial(n-1,m*n)
factorial(5,1)
在上面这个案例增加了一个m,m其实是保留了n*n-1*n-2……这样一个累乘器。
m永远拿到都是过去几次累乘的结果。