Scala語法
變量
val a: Int = 3
函數(shù)

函數(shù)文本:function literal
函數(shù)文本被編譯進一個類筑舅,類在運行期實例化的時候是一個函數(shù)值摊唇。函數(shù)文本和值的區(qū)別在于函數(shù)文本存在于源代碼烹俗,而函數(shù)值存在于運行期對象呀酸。
都是函數(shù)特質(zhì)trait Function[-S,+T]的實例
args.foreach(arg => println(arg))
函數(shù)文本的語法就是次酌,括號里的命名參數(shù)列表酣栈,右箭頭,然后是函數(shù)體。語法入下圖所示:

集合
Array可變羡玛,List,Tuple不可變
val a = Array(1,2,3) //Array[Int]
a(0) //1 //a.apply(0)
a(0) = 4 //a.update(0, 4)
val l = List(1,2,3) //List[Int]
l(1) //2
val t = (1,2,3) //Tuple[Int, Int, Int]
t._1 //1
//immutable mutable set
import scala.collection.mutable.Set //還有import scala.collection.immutable.Set
val movieSet = Set("Hitch", "Poltergeist") //scala.collection.mutable.Set[String]
movieSet += "Shrek"
//immutable mutable map
import scala.collection.mutable.Map
val treasureMap = Map[Int, String]()
treasureMap += (1 -> "Go to island.")
treasureMap += (2 -> "Find big X on ground.")
treasureMap += (3 -> "Dig.")
println(treasureMap(2))
//1 -> "Go to island"這樣的二元操作符表達式轉(zhuǎn)換為(1).->("Go to island.")耕陷。并返回一個包含鍵和值的二元元組
val romanNumeral = Map(
1 -> "I", 2 -> "II", 3 -> "III", 4 -> "IV", 5 -> "V"
)
println(romanNumeral(4))
//第一行里提及Map時溅话,你會得到缺省的映射:scala.collection.immutable.Map
Singleton對象
scala沒有static成員忍法,替代品是Singleton object
函數(shù)式對象 對象狀態(tài)不可改變
Scala編譯器將把你放在類內(nèi)部的任何不是字段的部分或者方法定義的代碼蛉顽,編譯進主構(gòu)
造器
//自動把整數(shù)轉(zhuǎn)換為分數(shù)的隱式轉(zhuǎn)換,隱式轉(zhuǎn)換要起作用斜纪,需要定義在作用范圍之內(nèi)鸟悴。如果你把隱式方法定義放在類
//Rational之內(nèi)徘铝,它就不在解釋器的作用范圍
implicit def intToRational(x: Int) = new Rational(x)
class Rational(n: Int, d: Int) { //n,d是類參數(shù)耳胎,只有在本類的方法中可以調(diào)用,不能調(diào)用其他Rational
require(d != 0) //實例的n,d
private val g = gcd(n.abs, d.abs)
val numer = n / g
val denom = d / g
def this(n: Int) = this(n, 1) //從構(gòu)造器
def +(that: Rational): Rational =
new Rational(
numer * that.denom + that.numer * denom,
denom * that.denom
)
def +(i: Int): Rational =
new Rational(numer + i * denom, denom)
override def toString = numer+"/"+denom
private def gcd(a: Int, b: Int): Int =
if (b == 0) a else gcd(b, a % b)
}
for表達式
for {子句} yield {循環(huán)體}
for (
file <- filesHere
if file.isFile;
if file.getName.endsWith(".scala")
) yield file
for{
p <- persons //生成器
n = p.name //定義
if(n startsWith "to") //過濾器
} yield n
捕獲異常惕它,match表達式
import java.io.FileReader
import java.io.FileNotFoundException
import java.io.IOException
try {
val f = new FileReader("input.txt")
// Use and close file
} catch {
case ex: FileNotFoundException => // Handle missing file
case ex: IOException => // Handle other I/O error
}
本地函數(shù)
import scala.io.Source
object LongLines {
def processFile(filename: String, width: Int) {
def processLine(line: String) {
if (line.length > width)
print(filename +": "+ line)
}
val source = Source.fromFile(filename)
for (line <- source.getLines)
processLine(line)
}
}
函數(shù)文本
val someNumbers = List(-11, -10, -5, 0, 5, 10)
someNumbers.filter((x:Int) => x > 0)
someNumbers.filter(x => x > 0)//短格式怕午,因為someNumbers是List[Int],所以可以省略Int類型
//_占位符淹魄,把下劃線當做一個或更多參數(shù)的占位符郁惜,只要每個參數(shù)在函數(shù)文本內(nèi)僅出現(xiàn)一次
someNumbers.filter(_ > 0)
偏應(yīng)用函數(shù):partially applied function
使用一個下劃線替換整個參數(shù)列表
someNumbers.foreach(println _)
someNumbers.foreach(println)
def sum(a: Int, b: Int, c: Int) = a + b + c
val a = sum _
a(1, 2, 3)
/*名為a的變量指向一個函數(shù)值對象。這個函數(shù)值是由Scala編譯器依照偏應(yīng)用函數(shù)表達式sum _甲锡,自動產(chǎn)生的類的一 *個實例兆蕉。編譯器產(chǎn)生的類有一個apply方法帶三個參數(shù)。之所以帶三個參數(shù)是因為sum _表達式缺少的參數(shù)數(shù)量為***三缤沦。Scala編譯器把表達式a(1,2,3)翻譯成對函數(shù)值的apply方法的調(diào)用虎韵,傳入三個參數(shù)1,2缸废,3包蓝。因此*a(1,2,3)是下列代碼的短格式:
*/
a.apply(1, 2, 3)
閉包
val more = 1
val addMore = (x:Int) => x + more
函數(shù)值是關(guān)閉這個開放術(shù)語(x: Int) => x + more的行動的最終產(chǎn)物,因此被稱為閉包
閉包捕獲的是變量本身企量,不是變量值测萎,所以閉包可以捕獲變量本身的改變
val someNumbers = List(-11, -10, -5, 0, 5, 10)
someNumbers.foreach(sum += _)
someNumbers.foreach((x: Int) => sum = sum + x)
重復(fù)參數(shù)
def echo(args: String*) = for (arg <- args) println(arg)
val arr = Array("What's", "up", "doc?")
echo(arr: _*)
_*標志告訴編譯器把arr的每個元素當做參數(shù),而不是作為單一的參數(shù)傳給echo
使用函數(shù)值和閉包減少代碼重復(fù)
def filesEnding(query: String) = filesMatching(query, _.endsWith(_))
def filesContaining(query: String) = filesMatching(query, _.contains(_))
def filesRegex(query: String) = filesMatching(query, _.matches(_))
def filesMatching(query: String,
matcher: (String, String) => Boolean) = {
for (file <- filesHere; if matcher(file.getName, query))
yield file
}
object FileMatcher {
private def filesHere = (new java.io.File(".")).listFiles
private def filesMatching(matcher: String => Boolean) =
for (file <- filesHere; if matcher(file.getName))
yield file
def filesEnding(query: String) = filesMatching(_.endsWith(query))
def filesContaining(query: String) = filesMatching(_.contains(query))
def filesRegex(query: String) = filesMatching(_.matches(query))
}
簡化代碼
def containsNeg(nums: List[Int]): Boolean = {
var exists = false
for (num <- nums)
if (num < 0)
exists = true
exists
}
def containsNeg(nums: List[Int]) = nums.exists(_ < 0)
curry化
def add(x:Int)(y:Int) = x + y
val second = add(1)_
second(2) //結(jié)果是3
second{2} //結(jié)果是3届巩,單個參數(shù)使用大括號硅瞧,看上去更像內(nèi)建控制結(jié)構(gòu)
叫名參數(shù):by-name parameter
var assertionsEnabled = true
def myAssert(predicate: () => Boolean) =
if (assertionsEnabled && !predicate())
throw new AssertionError
myAssert(() => 5 > 3)//不能使用myAssert(5 > 3)
def byNameAssert(predicate: => Boolean) =
if (assertionsEnabled && !predicate)
throw new AssertionError
myAssert(5 > 3)
抽象類
abstract class Element {
def contents: Array[String]
//空括號方法,子類可以通過字段和方法來實現(xiàn)
def height = contents.length
def width = if (height == 0) 0 else contents(0).length
}
擴展類 ... extends Element ...
這種extends子句有兩個效果:使類ArrayElement從類Element繼承所有非私有的成員,并且使ArrayElement成為Element的子類型
class ArrayElement(conts: Array[String]) extends Element {
def contents: Array[String] = conts
}
通常情況下姆泻,Scala僅為定義準備了兩個命名空間零酪,而Java有四個。Java的四個命名空間是字
段拇勃,方法,類型和包孝凌。與之相對方咆,Scala的兩個命名空間是:
- 值(字段,方法蟀架,包還有單例對象)
- 類型(類和特質(zhì)名)
Scala把字段和方法放進同一個命名空間的理由很清楚瓣赂,因為這樣你就可以使用val重載無參數(shù)的
方法榆骚,這種你在Java里做不到的事情
協(xié)變和逆變
trait Function1[-S, +T]{
def apply(x: S): T
}
class Publication(val title:String)
class Book(title: String) extends Publication(title)
object Library{
val books: Set[Book] =
Set(
new Book("scala book"),
new Book("java book")
)
def printBookList(info: Book => AnyRef){
for (book <- books) println(info(book))
}
}
def getTitle(p: Publication): String = p.title
Library.printBookList(getTitle)
for表達式
for(i <- 1 to 3; from = 4 -i; j <- from to 3) print ((10*i+j + " ")) //13 22 23 31 32 33
for(i <- 1 to 3; from = 4 -i; j <- from to 3 if i != j) yield 10*i+j //scala.collection.immutable.IndexedSeq[Int] = Vector(2, 3, 4)
== equals eq比較
val a = new String("abc")
val b = new String("abc")
a == b //true
a.equals(b) //true
a eq b //false,引用相等
樣本類和模式匹配
//1.添加類名工廠方法
case class Test(x:Int)
val a = Test(1) //替代 new Test(1)
//2.將參數(shù)列表中的所有隱式參數(shù)添加val前綴煌集,當成字段維護
a.x
//3.添加toString,hashCode,equals自然實現(xiàn)
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
case class Binop(operator:String, left:Expr,right:Expr) extends Expr
val op = Binop("+",Number(1.0),Var("x"))
op match {
case Binop(_,Number(1.0),_) => println(op.right)
case _ => println("not match")
}
val op = Unop("abc",Unop("abc",Var("-")))
## 變量綁定
## unchecked,模式窮舉性檢查被抑制
(op: @unchecked) match {
case Unop("abc", e @ Unop("abc", _)) => e
case _ => println("not match")
}
## option可選類
```scala
1.some(x),x為實際的值;2.None苫纤,缺失的值碉钠。
val line: Option[String] = None
val a = Map("111" -> "aaa","222" -> "bbb")
def show(x: Option[String]) = x match{
case Some(s) => s
case None => null
}
a.get("111")返回值為Some(value),Some(aaa)// Option[String] = Some(aaa)
a.get("111").orNull返回值或者null
for表達式匹配
val a = List(Some("apple"),None,Some("origin"))
for(Some(fruit) <- a) println(fruit)
list模式匹配
def iSort(xs: List[Int]): List[Int] = xs match{
case List() => List()
case x :: xs1 => insert(x, iSort(xs1))
}
def insert(x:Int, xs: List[Int]): List[Int] = xs match{
case List() => List(x)
case y :: ys => if(x<=y) x::xs else y::insert(x,ys)
}
iSort(List(4,1,3))
列表一階函數(shù)
val a = List(1,2,3)
a.toString //String = List(1, 2, 3)
a.toArray //Array[Int] = Array(1, 2, 3)
a mkString (prfix,sep,posfix)
a.copyToArray(array,len)
"abc".toList //List[Char] = List(a, b, c)
列表高階函數(shù)
xs map f
val words = List("abc","de","g")
words map (_.length) //List(3,2,1)
words flatMap (_.toList) //List[Char] = List(a, b, c, d, e, g)
var sum = 0
List(1,2,3) foreach (sum+=_)//返回類型為Unit, sum=6
List(1,2,3,4) filter (_>2)//List[Int] = List(3, 4)
List(1,2,3,4) partition (_>2)//(List[Int], List[Int]) = (List(3, 4),List(1, 2))
List(1,2,3,0) takeWhile (_>0) //List(1,2,3) 返回列表中最長能滿足右操作元的前綴
List(List(1,2,3,0) span (_>0)) //List[(List[Int], List[Int])] = List((List(1, 2, 3),List(0)))
List(1,2,-1) forall (_ > 0) //Boolean = false
List(1,2,-1) exists (_ > 0) //Boolean = true
List(1,4,2) sortWith (_ < _) //List(1, 2, 4)
抽象成員
class test(a:Int,b:Int) //a,b初始化在調(diào)用構(gòu)造函數(shù)之前
trait test1{
val a:Int
val b:Int
}
class test2 extends test1{ //抽象成員a,b初始化在構(gòu)造函數(shù)之后
val a = 1
val b = 2
}
//或者下面
new test1{
val a = 1
val b = 2
}
class test3 extends{
val a = 1
val b = 2
}with test1 //預(yù)初始化字段喊废,在調(diào)用超類之前,trait不像類可以使用類參數(shù)初始化
//或者下面
new {
val a = 1
val b = 2
}with test1
抽象類型
class Food
abstract class Animal{
def eat(food:Food)
}
class Grass extends Food
class Cow extends Animal{
def eat(food:Food) = println("Cow eat Grass")
}
class Fish extends Food
(new Cow) eat (new Fish)//正常執(zhí)行
class Food
abstract class Animal{
type SuitableFood <: Food
def eat(food:SuitableFood)
}
class Grass extends Food
class Cow extends Animal{
type SuitableFood = Grass
def eat(food:Grass) = println("Cow eat Grass")
}
class Fish extends Food
(new Cow) eat (new Fish)//失敗
枚舉
object color extends Enumeration{
val Red,Green,Blue = Value
}
color.values.foreach(println)
color.Red.id //0
color(0)//Red
隱式轉(zhuǎn)換和參數(shù)
隱式轉(zhuǎn)換為期望類型
val a:Int = 3.5 //error
implicit def doubleToInt(x:Double) = x.toInt
val a:Int = 3.5 //3
轉(zhuǎn)換方法接受者
class Rational(n:Int, d:Int){
def +(that:Rational):Rational = ......
def +(that:Int):Rational = ......
}
implicit def intToRational(x:Int) = new Rational(x,1)
1 + (new Rational(2,1))
隱式參數(shù)
class PreferredPrompt(val preference:String)
object Greeter{
def greet(name:String)(implicit prompt:PreferredPrompt){
println("welcome," + " name " + ". The system is ready.")
println(prompt.preference)
}
}
object JoesPerfs{
implicit val promptArg = new PreferredPrompt("implict args")
}
import JoesPerfs._
case class StringOrder(a:String) extends Ordered[StringOrder]{
override def compare(that:StringOrder) = this.a.length - that.a.length
}
def maxListUpBond[T <: Ordered[T]](elements:List[T]): T =
elements match{
case List() => throw new RuntimeException("empty list")
case List(x) => x
case x :: rest =>
val maxRest = maxListUpBond(rest)
if(x > maxRest) x else maxRest
}
//這個函數(shù)的參數(shù)不能是List(1,2,3),因為Int類不是Ordered[Int]的子類型
def maxListUpBond[T](elements:List[T])(implicit order:T => Ordered[T]): T =
elements match{
case List() => throw new RuntimeException("empty list")
case List(x) => x
case x :: rest =>
val maxRest = maxListUpBond(rest) //相當于maxListUpBond(rest)(order) 作用1:用隱身值補充這個參數(shù)
if(x > maxRest) x else maxRest //相當于order(x) > maxRest 作用2:將這個參數(shù)當做可用的隱式操作而使用于方法體中
}
//視界 T <% Ordered[T],任何T都好污筷,只要可以被當做Ordered[T]
def maxListUpBond[T <% Ordered[T]](elements:List[T]): T =
elements match{
case List() => throw new RuntimeException("empty list")
case List(x) => x
case x :: rest =>
val maxRest = maxListUpBond(rest)
if(x > maxRest) x else maxRest
}
scala> def lessThan[T <% Ordered[T]](x : T, y : T) = x < y
lessThan: [T](x: T, y: T)(implicit evidence$1: T => Ordered[T])Boolean
抽取器(extrators)
object Email{
def apply(user:String ,domain:String) = user + "@" + domain
def unapply(str:String): Option[(String,String)] = {
val parts = str split "@"
if(parts.length == 2) Some(parts(0),parts(1)) else None
}
}
val selectorString = Email("163","com")
val selectorString = "test@net"
selectorString match {
case Email(user,domain) => println("user is:"+user+",domain is:"+domain)
}
Email.unapply(selectorString)
object Twice{
def apply(s:String) = s + s
def unapply(s:String): Option[String] = {
val len = s.length/2
val half = s.substring(0,len)
if (half == s.substring(len)) Some(half) else None
}
}
object UpperCase{
def unapply(s:String): Boolean = s.toUpperCase == s
}
def userTwiceUpper(s:String) = s match{
case Email(Twice( x @ UpperCase()),domain) => "user is:"+x+",domain is:"+domain
case _ => None
}
模式守衛(wèi)
case n:Int if 0 < n => ......
## actor
```scala
import scala.actors._
object SillyActor extends Actor{
def act() {
for (i<- 1 to 5){
println("i is:"+i)
}
}
}
SillyActor.start()
//第二種方式,不需要調(diào)用start
import scala.actors.Actor._
val actor2 = actor{
for(i <- 1 to 5) println("i am actor 2")
}
val echoActor = actor{
while(true){
for(i <- 1 to 5) println("i am actor 2")
receive{
case msg => println("received msg:"+msg)
}
}
}
echoActor ! "Hi there"
偏應(yīng)用函數(shù)
val second:List[Int] => Int = {
case x :: y :: _ => y
}
val third:PartialFunction[List[Int],Int] = {
case x::y::_ => y
}
def test1(f:PartialFunction[List[Int],Int]):Nothing = {
val a = List(1,2,3)
println("result is:"+f(a))
throw new RuntimeException("")
}
test1{
case x::y::_ => y
}