val v1 = 2;//变量,不能重新赋值,函数式语言大量提倡使用val变量,Erlang所有的变量都是val的 var v2 = 3;//变量,和Java的变量一致 def v3 = v1 * v2;//只是定义v1*v2表达式的名字,并不求值,在使用的求值
lazy val lazyVal = { println("I'm too lazy"); 1 } println("after lazyVal") val x = lazyVal
打印出:
after lazyVal
I'm too lazy
二、表达式:
For comprehensioon
val dogBreeds = List("Doberman", "Yorkshire Terrier", "Dachshund", "Scottish Terrier", "Great Dane", "Portuguese Water Dog") for (breed <- dogBreeds) println(breed) for(bread <- dogBreads if bread.contains("Terrier"); if !bread.contains("Yorkshire"); )println(bread) //yield val filteredBreeds = for { breed <- dogBreeds if breed.contains("Terrier") if !breed.startsWith("Yorkshire") } yield breed
避免使用显式返回
三、条件控制:
while,do...while没有什么特别
if...else
for 表达式:
val filesHere = (new java.io.File(".")).listFiles for (file <- filesHere) println(file) for(i <- 1 to 4){//和Ruby中的1..4一样 println(i) } for(i <-1 util 4){//和Ruby中的1...4一样 println(i) }
一切表达式都有返回值,条件控制语句也不例外
val v1 = if(true) 1 else 0
四、函数式编程:
1、一切操作都是函数调用:
1 + 1 等价于 1.+(1)
for (i <- List(1, 2)) {
println(i)
}
//for是函数调用
2、一切函数都可以作为操作符使用:
1 max 2
3、函数嵌套:
def sqrt(x: Double) = { def sqrtIter(guess: Double, x: Double): Double = if (isGoodEnough(guess, x)) guess else sqrtIter(improve(guess, x), x) def improve(guess: Double, x: Double) = (guess + x / guess) / 2 def isGoodEnough(guess: Double, x: Double) = abs(square(guess) x) < 0.001 sqrtIter(1.0, x) }
4、函数是一等公民:
(x: Int) => x + 1//匿名函数 var inc = (x: Int) => x + 1//赋值给一个变量 inc(10)
val someNumbers = List(-11,-10,-5,0, 5, 10) someNumbers.foreach((x: Int) => println(x)) someNumbers.filter((x: Int) => x > 0)
利用类型推到简化:
someNumbers.foreach(x => println(x))
使用占位符语法(Placeholder syntax)
someNumbers.filter(_ > 0)
使用Partially applied functions
someNumbers.foreach( println _ )
由于foreach期望一个函数作为参数,所以可以简化为
someNumbers.foreach(println)
5、闭包:
var more = 1 var addMore = (x: Int) => x + more addMore(10)
结果是11
闭包绑定的是定义时的变量,而不是值
var more = 2 addMore(10)
结果是12
6、尾递归:
递归函数在最后一个操作调用自身
def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b)
7、偏函数(Partial Function)
def concatUpper(s1: String, s2: String): String = (s1 + " " + s2).toUpperCase val c = concatUpper("hello,",_:String) c("world")
偏函数的类型是PartialFunction,他是一个trait,定义了一个函数orElse
val truthier: PartialFunction[Boolean, String] = { case true => "truthful" } val fallback: PartialFunction[Boolean, String] = { case x => "sketchy" } val tester = truthier orElse fallback println(tester(1 == 1)) println(tester(2 + 2 == 5))
8、curry化:
def cat(s1: String)(s2: String) = s1 + s2 val c1 = cat("hello,") c1("world)
普通函数可以转化成curry化的:
def cat(s1: String)(s2: String) = s1 + s2 var carryCat = Function.curried(cat _) cat("hello,")("world")
9、隐式转换:
Scala有一些常用的类型都有一个RichXxx类型:
4 max 3 就是自动转化成为 RichInt类型
val name: String = "scala" println(name.capitalize.reverse)
java.lang.String中没有capitalize和reverse,通过
隐式转换成RichString来实现的,Predef里面定义了
implicit def stringWrapper(x: String) = new runtime.RichString(x)
隐式转换函数都用implicit修饰。
10、隐式函数参数(Implicit Function Parameters):
隐式参参数可以在上下文中找到并绑定到同名的变量:
def multiplier(i: Int)(implicit factor: Int) { println(i * factor) } implicit val factor = 2 multiplier(2) multiplier(2)(3)
11、call-by-value or call-by-name
def f(x: Int) = x//call-by-value def f(x: => Int) = x//call-by-name(参数类型前面带有=>) //使用call-by-name构建自己的流程控制语句 def myWhile(conditional: => boolean)(f: => Unit){ if(conditional) f myWhile(conditional)(f) } var count = 0 myWhile( count < 5){ println("still loop while"); count += 1 }
12、模式匹配:
函数式语言最重要的概念模式匹配:
匹配常量:
def fib(in: Int): Int = in match{ case n if n <= 0 => 0 case 1 => 1 case n => fib2(n-1) + fib2(n-2) }
可以匹配任何类型:
def activity(day: String){ day match{ case "Sunday" => print("Eat, sleep,repeat...") case "Saturday" => print("Hangout with friends...") case "Monday" => println("...code for fun...") } }
常量匹配和Java的switch...case类似,变量匹配使得变量得副作用而得到匹配的值。
元组匹配:
def coordinates(intput: Any){ input match{ case (x,y) => printf("x=%d,y=%d",x,y); case _ => Nothing } }
List匹配:
def sumOdd(in: List[Int]): Int in match{ case Nil => 0 case x::rest if x % 2 == 1 => x + sumOdd(rest) case _::rest => sumOdd(rest) }
类型匹配:
def typeMatch(in: Any) = in match{ case s: String => "String, length " + s.length case i: Int if i > 0 => "Natural Int" case i: Int => "Another Int" case a: AnyRef => a.getClass.getName case _ => "null" }
类似于java的instanceof
case class:
case class Person(name: String,age:Int) val p = Person("Smith" 20)
equals,hashcode,accessor all ok
case class匹配:
case class Apple() case class Orange() case class Book() def accept(thing: Any){ thing match{ case Apple() => println("Apple") case Orangle() => println("Orange") case Book() => println("Book") case _ => println("Not accepted") } }
Sealed class:
匹配的case class是无法穷举的,Sealed class只能在和他相同的文件中定义子类,所以只需要关注
当前文件的case class匹配的列举,并且如果列举不全则编译时有Warning。
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 def describe(e: Expr): String = e match{ case Number(x) => "a number" case Var(_) => "a variable" }
编译的时候会有Waring:
warning: match is not exhaustive!
missing combination UnOp
missing combination BinOp
正则表达式作为Extractor
def process(input: String){ val MatchStock = """^(.+):(\d*\.\d+)""".r input match{ case MatchStock("GooG", price) => println("Price Of GooG is " + price) case MatchStock("IBM",price) => println("Price of IBM is " + price) case _ => println("No data for access") } } prcoess("GooG:310.84")
13、Stream:
五、面向对象:
1、一切皆是对象
//值也是对象
123.toByte true.toString val compare = (x: Int, y: Int) = x > y//函数也是值
2、单例对象:
object Singleton{ val v = 1; }
main函数都是写在伴生对象中的
3、没有静态成员:
以为他们的实例也必须是对象的实例
object Dog { val whatever = "dog" // static field in Java }
4、主构造函数:
class Rational(n: Int,d: Int){//主构造函数 def this(n: Int) = this(n,1)////Auxiliary constructors }
5、访问子:
没有声明为private的字段自动生成getter,setter方法:
class Time { var hour = 12 var minute = 0 }
等价于:
class Time { private[this] var h = 12 private[this] var m = 0 def hour: Int = h def hour_=(x: Int) { h = x } def minute = m def minute_=(x: Int) { m = x } }
6、覆写override:
覆写关键词是必须的(抽象的是可选的),而不像java的@override是可选的:
class Rational(n: Int, d: Int) extends AnyRef { //...other code override def toString = "" + numer + "/" + denom }
不光可以覆写函数,还可以覆写字段
class AbstractParent { def name = "parent"; } class ConcreteChild extends AbstractParent { override val name = "Child" }
6、伴生对象:
和类名一样的单例对象成为伴生对象。
在伴生对象中的类和Java的静态成员类似。
7、抽象类型:
类、方法、字段和类型都可以为抽象的。
abstract class AbstractParent {//抽象类 def name: String//抽象字段 } class ConcreteChild extends AbstractParent { val name = "Child"//覆写集成的字段,由于父类是抽象的,所以可以省略override字段 } println(new ConcreteChild().name)
8、方法和字段不可以重名:
方法和字段被设置为统一命名空间。无参方法可以省略括号。
7、操作符重载
scala允许操作符作为函数名,使用重载和定义普通的函数类似。
def +()
重载+隐式转换经常一起使用
比c++简单:c++使用operator()+ 和使用operator()进行重载和类型隐式转换,并且
区分为成员还是友元重载。
待补充....
六、类型体系:
待补充...
七、DSL
待补充...
八、Actor