一、变量:
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