由于Spark项目须要,学习Scala编程。html
从官网文档入手:http://www.scala-lang.org/documentation/java
首先从他的Older Documentation入手。程序员
第一篇是Brief Scala Tutorialexpress
只有20页,对于有Java基础的人来讲上手很快编程
其中有几点值得注意数据结构
object Timer {
def oncePerSecond(callback: () => Unit) { while (true) { callback(); Thread sleep 1000 }
}
def timeFlies() { println("time flies like an arrow...") }
def main(args: Array[String]) { oncePerSecond(timeFlies)}
}
官网给出的解释是ide
The type of this function is written () => Unit and is the type of all functions which take no arguments and return nothing (the type Unit is similar to void in C/C++). 函数式编程
这段不知道怎么翻译合适。函数
(2)匿名方法post
object TimerAnonymous { def oncePerSecond(callback: () => Unit) { while (true) { callback(); Thread sleep 1000 } } def main(args: Array[String]) { oncePerSecond(() => println("time flies like an arrow...")) } }
用匿名方法的话编程更简单直白,在main方法中直接用=>分开了方法名参数及方法体。和上面的例子效果是相同的。
(3)Scala的class能够带参数:
class Complex(real: Double, imaginary: Double) { def re() = real def im() = imaginary }
这样的语句定义了一个单例对象:一个有且仅有一个实例的类。object语句在定义了一个叫HelloWorld的类的同时还定义了一个叫HelloWorld的实例。这个实例在第一次使用的时候会进行实例化。聪明的读者可能会发现main函数并无使用static修饰符,这是因为静态成员(方法或者变量)在Scala中并不存在。Scala从不定义静态成员,而经过定义单例object取而代之。
在def re()=real中没有指定返回值类型,而是由编译器根据“=”右边的类型来判断该方法的返回值类型。固然编译器不是总能推断出正确的变量类型,这就须要编程人员在编程初期尝试去掉变量类型定义,若是编译器不报错的话就表示他能够推断类型,若是报错就仍是老老实实地把类型加上。等到编的多了就知道什么能够什么不能够了。
固然,这里的re()和im()的括号是能够去掉的。
class Complex(real: Double, imaginary: Double) {
def re = real def im = imaginary }
(4)继承与重写
class Complex(real: Double, imaginary: Double) {
def re = real def im = imaginary override def toString() = "" + re + (if (im < 0) "" else "+") + im + "i"
}
若是子类的方法重写了父类的方法,必需要有override修饰语
若是一个类没有继承任何类的话,隐式继承scala.AnyRef
(5)case class
对于处理树结构的数据很适用
abstract class Tree case class Sum(l: Tree, r: Tree) extends Tree
case class Var(n: String) extends Tree case class Const(v: Int) extends Tree
以上的Sum,Var和Const就是case class,与标准的class有如下几个区别
val x = Var("x")
Console.println(x.name)
模式匹配的东西有点难,
def eval(t: Tree, env: Environment): Int = t match { case Sum(l, r) => eval(l, env) + eval(r, env)
case Var(n) => env(n) case Const(v) => v }
一个熟练的面向对象的程序员可能想知道为何咱们不吧eval定义为Tree或者其之类的成员函数。咱们事实上能够这么作。由于Scala容许条件类象普通类那样定义成员。决定是否使用模式匹配或者成员函数取决于程序员的喜爱,不过这个取舍还和可扩展性有重要联系:
当你使用成员函数时,你能够经过继承Tree从而很容易的添加新的节点类型,可是另一方面,添加新的操做也是很繁杂的工做,由于你不得不修改Tree的全部子类。
当你使用模式匹配是,形势正好逆转过来,添加新的节点类型要求你修改全部的对树使用模式匹配的函数,可是另外一方面,添加一个新的操做只须要再添加一个模式匹配函数就能够了。
下面是模式匹配里的对符号求导数
首先看下导数的性质:
def derive(t: Tree, v: String): Tree = t match { case Sum(l, r) => Sum(derive(l, v), derive(r, v)) case Var(n) if (v == n) => Const(1) case _ => Const(0) }
def main(args: Array[String]) { val exp: Tree = Sum(Sum(Var("x"),Var("x")),Sum(Const(7),Var("y")))
val env: Environment = { case "x" => 5 case "y" => 7 }
println("Expression: " + exp) println("Evaluation with x=5, y=7: " + eval(exp, env))
println("Derivative relative to x:\n " + derive(exp, "x"))
println("Derivative relative to y:\n " + derive(exp, "y")) }
(6)traits
Scala的traits和Java中的interface相似,但有别于interface的是traits能够实现部分方法,而且能够继承多个。
Tutorial里的例子不是很直观,因而摘了网上的一个例子[1]
abstract class Animal { def walk(speed:Int) def breathe() = { println("animal breathes") } }
这里的抽象类Animal定义了walk方法,实现了breathe方法。
再看下Flyable和Swimable两个trait的实现:
trait Flyable { def hasFeather = true def fly }
trait Swimable { def swim }
注意Flyable trait中有两个方法,一个是hasFeather方法,这个方法已经实现了,另外一个方法是fly方法,这个方法只是定义没有实现,而Swimable trait只是定义个一个swim的方法,没有具体实现。
下面咱们定义一种动物,它既会飞也会游泳,这种动物是鱼鹰 FishEagle,咱们看下代码:
class FishEagle extends Animal with Flyable with Swimable { def walk(speed:Int) = println("fish eagle walk with speed " + speed) def swim() = println("fish eagle swim fast") def fly() = println("fish eagle fly fast") }
在类的实现中须要实现抽象类Animal的walk方法,也须要实现两个特征中定义的未实现方法。
下面main方法代码:
object App { def main(args : Array[String]) { val fishEagle = new FishEagle val flyable:Flyable = fishEagle flyable.fly val swimmer:Swimable = fishEagle swimmer.swim } }
在main方法中,咱们首先初始化了一个FishEagle对象,而后经过Flyable和Swimable trait来分别调用其fly和swim方法,输出结果以下:
fish eagle fly fast fish eagle swim fast
trait的使用方法就是这样子了,它很强大,抽象类能作的事情,trait均可以作。它的长处在于能够多继承。
trait和抽象类的区别在于抽象类是对一个继承链的,类和类以前确实有父子类的继承关系,而trait则如其名字,表示一种特征,能够多继承。
还有一个特色就是with:用关键字with能够混入更多的trait。若是类已经继承了类,就可使用with混入trait。
class Animal class Dog(val name: String) extends Animal with Friend{}
咱们还能够在实例一级进行混入,这样的话就能够把特定的类的实例当作trait
class Cat(val name: String) extends Animal val scat = new Cat("cat") with Friend //这样scat就是Friend了
(7)泛型
参考文献
【1】scala入门教程:scala中的trait