lang
Java++:增加的語法 -》純OO;操作符重載;closure;使用trait進行mixin組合;existential type(_);抽象類型(type T) class C1[T]{...};模式匹配 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??Java--:刪減的語法-》 靜態成員;原生數據類型;break、continue;接口;通配符List, import pkg.*;;原始類型class C1<T> {...};enum枚舉
注:existential type——和Java互操作時進行對應,?Iterator? -->? Iterator[T] { type T <: Component }或者Iterator[_]
2.1.2.庫:以下功能通過庫的形式提供:assert,enum,property,event,actor,resource control(自動釋放),query
abstract case catch class def?do else extends false final?finally for if implicit import?match new null object override?package private protected requires return?sealed super this throw trait?try true type val var while with yield??_ ? ? ?: ? ? = ? ? => ? ?<- ? ?<: ? <% ? ? ?>: ? ? ?# ? ? ? ?@ ?(弄清出這些符號的含義) ??Scala調用Java的方法時,會碰到有Scala的保留字,如Thread.yield();?這在Scala中是非法的,專門有個解決辦法,寫成:Thread.`yield`() ??注意:沒有break和continue
這些標識在Java中是非法的,在Scala中是合法的,可以當作函數名使用,使接口更加DSL:val empty_? = true ? ? ? ??val + = "hello" ? ? ? ? val `yield` = 10 ? ? ?val ** = "power" (經常看不懂)?注意:可用但可讀性不好
2.2.3.1val, var
var可變,可重新賦值,賦值為"_"表示缺省值(0, false, null),例如:var d:Double = _ // d = 0.0 ;?var i:Int = _ // i = 0 ?; ?var s:String = _ // s = null ? ?; ??var t:T = _? //泛型T對應的默認值?注意:僅 var可用"_"表示缺省值賦值。 使用val _ 缺省 會在運行時報錯:unbound placeholder parameter
val不可變,相當于const/final,但如果val為數組或者List,val的元素可以賦值;val pi = 3. //相當于3.0d ;?val pi = 3.f //相當于3.0f?提示:向函數式風格推進的一個方式,就是嘗試不用任何var來定義變量。
2.2.3.2花樣定義
和Python一樣方便的賦值方式:val x,y = 0 //賦同一初始值 ;val (x,y) = (10, "hello") //同時定義多個變量,注意:val x,y=10,"hello"是錯誤的 ;?val x::y = List(1,2,3,4)? // x = 1, y = List(2,3,4) ?val List(a,b,c) = List(1,2,3) // a = 1, b = 2, c = 3 ;?val Array(a,b,_, _,c@_*) = Array(1,2,3,?4,5,?6,?7)? //也可以用List,Seq ?a // 1 ?b // 2?c // Array(5, 6, 7), _*匹配0個到多個
使用正則表達式定義:val regex = "(\\d+)/(\\d+)/(\\d+)".r ?val regex(year, month, day) = "2010/1/13"?// year: String = 2010; ?// month: String = 1;// day: String = 13
2.2.3.3lazy, val, def的區別
val:定義時就一次求值完成,保持不變?val f = 10+20 // 30
lazy:定義時不求值,第一次使用時完成求值,保持不變?lazy f = 10+20 //?f // 30
def:定義時不求值,每次使用時都重新求值?(無參,缺省返回值類型的函數定義)def f = 10+20 // 30?def t = System.currentTimeMillis //每次不一樣
scala>val f1 = System.currentTimeMillis ?f1: Long = 1279682740376? ??//馬上求值 ?scala>f1 ?res94: Long = 1279682740376 //之后保持不變?scala>lazy val f2 = System.currentTimeMillis?f2: Long = ? //定義時不求值?scala>System.currentTimeMillis?res95: Long = 1279682764297?scala>f2?res96: Long = 1279682766545//第一次使用時求值,注意:6545 > 4297?scala>f2?res97: Long = 1279682766545//之后保持不變?scala>def f3 = System.currentTimeMillis?f3: Long?scala>f3 ?res98: Long = 1279682784478//每次求值?scala>f3?res99: Long = 1279682785352//每次求值
盡量使用大寫形式:Int, Long, Double, Byte, Short, Char, Float, Double, Boolean,編譯時Scala自動對應到Java原始類型,提高運行效率。Unit對應java的void,用asInstanseOf[T]方法來強制轉換類型:def i = 10.asInstanceOf[Double] // i: Double = 10.0?List('A','B','C').map(c=>(c+32).asInstanceOf[Char]) // List('a','b','c') ?用isInstanceOf[T]方法來判斷類型:?val b = 10.isInstanceOf[Int] // true; ?而在match ... case中可以直接判斷而不用此方法。
用Any統一了原生類型和引用類型。
-3 abs // 3 ;?-3 max -2 // -2 ;?-3 min -2 // -3 ;1.4ound // 1四舍五入;?1.6 round // 2四舍五入;?1.1 ceil // 2.0 天花板?1.1 floor // 1.0地板?注:Rich Wrapper operations
無++,--操作,但可以+=, -=,如下:var i = 0?i++ ?//報錯,無此操作; i+=1 // 1 ;?i--? //報錯,無此操作;?i-=1 // 0 ?def even(n:Int) = 0==(n & 1) ?def odd(n:Int) = !even(n)
String可以轉化為List[Char]?在String上做循環,其實就是對String中的每一個Char做操作,如:?"jamesqiu" max // 'u'?"jamesqiu" min // 'a'?('a' to 'f') map (_.toString*3) // (aaa, bbb, ccc, ddd, eee, fff)
可以表示很大的整數:BigInt(10000000000000000000000000) //報錯; ?BigInt("10000000000000000000000000") // scala.math.BigInt = 10000000000000000000000000
例如:def? fac(n:Int):BigInt = if (n==0) 1 else fac(n-1)*n?fac(1000)?或者寫成:def fac2(n:Int) = ((1:BigInt) to n).product?// res1: BigInt = 9332621544394415268169923885626670049071596826438......000000000000000000
"..."或者"""...""""
println("""|Welcome?to?Ultamix?3000.
|Type?"HELP"?for?help.""".stripMargin)
輸出:
Welcome?to?Ultamix?3000.
Type?"HELP"?for?help.
scala中,字符串除了可以+,也可以* ? ??"abc" * 3// "abcabcabc" ? ? ?"abc" * 0// "" ?例子: ?"google".reverse // "elgoog" ? ?"abc".reverse.reverse=="abc" // true ; ?"Hello" map (_.toUpper) //相當于"Hello".toUpperCase
"101".toInt // 101,無需Integer.parseInt("101"); ??"3.14".toFloat // 3.14f ? ; ??101.toString ?; ?3.14.toString ? ; ? ?轉換整個列表:List("1","2","3") map (_.toInt) // List(1,2,3)?或者?List("1","2","3") map Integer.parseInt // List(1,2,3)
val sb = new StringBuilder ??sb += 'H' ??sb ++= "ello" ?sb.toString // "Hello"?sb clear // ?StringBuilder()
使用java.text.MessageFormat.format:?val?msg = java.text.MessageFormat.format(?"At{1,time}on{1,date}, there was{2}on planet{0}.","Hoth",newjava.util.Date(),"a disturbance in the Force") ??輸出?At17:50:34on2010-7-20, there wasa disturbance in the Forceon planetHoth. ?方法2:?"my name is %s, age is %d."format("james", 30)//my name is james, age is 30.?注意:format還可以這么用?"%s-%d:%1$s is %2$d."format("james", 30)//james-30:james is 30. ??"%2$d age's man %1$s: %2$d"format("james", 30) //30 age's man james: 30
Null:?Trait,其唯一實例為null,是AnyRef的子類,*不是*AnyVal的子類
Nothing:?Trait,所有類型(包括AnyRef和AnyVal)的子類,沒有實例
None:Option的兩個子類之一,另一個是Some,用于安全的函數返回值
Unit:無返回值的函數的類型,和java的void對應
Nil:?長度為0的List
Scala的==很智能,他知道對于數值類型要調用Java中的==,ref類型要調用Java的equals() ?"hello"=="Hello".toLowerCase() ?在java中為false,在scala中為true ;?Scala的==總是內容對比基本類型Int,Double,比值,?其他類型?相當于A.equals(B) ? ?eq才是引用對比
例如:val s1,s2 = "hello" ?val s3 = new String("hello") ?s1==s2 // true ??s1 eq s2 // true ??s1==s3 // true值相同 ?s1 eq s3 // false不是同一個引用
Option[T]可以是任意類型或者空,但一旦聲明類型就不能改變;Option[T]可完美替代Java中的null,可以是Some[T]或者None;Option實現了map, flatMap, and filter接口,允許在'for'循環里使用它;
函數返回值能被統一處理了:
沒有Option的日子 def find(id:Long):Person = ...? 返回Person或者null? 返回null不特殊處理會拋:NullPointerExceptions? 類比:Java的Stringx.split返回null
現在:?def find(id:Long):Option[Person] = ...?返回Some[Person]或者None?返回值直接getOrElse或者列表操作?類比:Java的Stringx.split返回new String[0]
結論:函數永遠不要返回null值,如果輸入有問題或者拋異常,返回Option[T]
參數有效性檢查沒有那么煩人了:沒有Option的日子: def blank(s:String) =if (s==null) false else{s.toList.forall(_.isWhitespace) } ??現在:?def blank(s:String) =Option(s).toList.forall(_.forall(_.isWhitespace))?結論:盡可能地不要浪費代碼去檢測輸入,包裝成Option[T]來統一處理
Some(3).getOrElse(4) // 3 ? ?None.getOrElse(4) // 4 ? ?打印key=3的value:寫法1:def p(map:Map[Int,Int]) = println(map(3))?p(Map(1->100,2->200)) //拋異常?寫法2:def p(map:Map[Int,Int]) = println(map get 3 getOrElse "...") ?p(Map(1->100,2->200)) // ... ? ?p(Map(1->100,3->300)) // 300
例子1:defm(k:Int) = {Map((1,100),(2,200),(3,300)) get(k) match {?case Some(v) =>?k+": "+v ?case None =>?"not found"?}}
def main(args:Array[String]) :Unit= {?println(m(1)) // 100 ??println(m(2)) // 200 ??println(m(3)) // 300 ?println(m(4)) // "not found"?println(m(-1)) // "not found"?}
例子2:val l = List(Some(100),None, Some(200), Some(120),None) ?for (Some(s) <- l) yields// List(100, 200, 120) ?或 ?l?flatMap (x=>x)// List(100, 200, 120)
例子3:Option結合flatMap?def toint(s:String) =?try { Some(Integer.parseInt(s)) } catch { case e:Exception => None } ?List("123", "12a", "45") flatMap toint // List(123, 45) ?List("123", "12a", "45") map toint // List(Some(123), None, Some(45))
<- ? ??for (i <- 0 until 100) ??用于for循環,符號∈的象形
=> ? ??List(1,2,3).map(x=> x*x) ??((i:Int)=>i*i)(5) // 25 ? ? ?用于匿名函數 ?也可用在import中定義別名:import javax.swing.{JFrame=>jf}
->?Map(1->"a",2->"b")?用于Map初始化,也可以不用->而寫成Map((1,"a"),(2,"b"))
Java里面的寫法:switch(n) {?case(1): ...; break;?case(2): ...; break;?default: ...;?} ? ? ? ? ? ? ? ? ? ? ? Scala寫法:def m(n:String) =?n match {?case "a"|"b"=>... //這個比較好 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?case "c" =>...?case _ =>...?}?匹配值每個case..=>結束不用寫break了,_相當于default
match可以很簡單地匹配數據類型(不需要isInstanceOf[T]):def f(v:Any) = v match {case null => "null" ?case i:Int => i*100?case s:String => s ?case _ => "others"?}?注意:上面case中的i、s都叫模式變量 ??f(null) // "null" ? ?f(5) // 500 ??f("hello") // "hello" ??f(3.14) // "others" ?注意:自定義類型如果也要匹配,需要用case class
/** Basic command line parsing. */
object?Main { ?var?verbose =?false?//記錄標識,以便能同時對-h和-v做出響應
def?main(args: Array[String]) {
for(a <- args) ?a?match{?case"-h"|"-help"=>?println("Usage: scala Main [-help|-verbose]")
case"-v"|"-verbose"=> ?verbose =true
case?x?=>?//這里x是臨時變量 ??println("Unknown option: '"+ x +"'")?}
if(verbose) println("How are you today?") ?}?}
寫法1:def fac(n:Int):Int = n match { ?case 0=>1 ??case _=>n*fac(n-1) ?}
寫法2(使用映射式函數):def fac: Int=>Int = {?case 0=> 1 ? ?case n=> n*fac(n-1) ?}
寫法3(使用尾遞歸):def fac: (Int,Int)=>Int= {?case (0,y) =>y?case(x,y) =>fac(x-1,x*y)?}?fac(5,1) // 120
寫法4(reduceLeft):def fac(n:Int) = 1 to n reduceLeft(_*_)?implicit def foo(n:Int) = new { def ! = fac(n) } ??5!// 120
寫法5:(最簡潔高效)?def fac(n:Int) = (1:BigInt) to n product?fac(5) // 120
常量匹配很簡單,即case后跟的都是常量;
變量匹配需要注意,case后跟的是match里面的臨時變量,而不是其他變量名:
3 match {?case i => println("i=" + i) //這里i是模式變量(臨時變量),就是3?}
val a = 10?20 match { case a => 1 } // 1,a是模式變量,不是10
為了使用變量a,必須用`a`:20 match { case`a`=> 1; case b => -1 } // -1,`a`是變量10?或者用大寫的變量:val A = 10?20 match { case A=> 1; case b => -1 } // -1,大寫A是變量10
寫法1:
(1 to 20) foreach {case?x?if(x % 15 == 0) => printf("%2d:15n\n",x)?case?x?if(x % 3 == 0) ?=> printf("%2d:3n\n",x)?case?x?if(x % 5 == 0) ?=> printf("%2d:5n\n",x)?case?x => printf("%2d\n",x) }
(1 to 20) map ( x => (x%3,x%5) match {?case(0,0)=> printf("%2d:15n\n",x) ?case(0,_)=> printf("%2d:3n\n",x) ?case(_,0)=> printf("%2d:5n\n",x)?case(_,_)=> printf("%2d\n",x)?})
var f = openFile()
try{?f = new FileReader("input.txt")?} catch {?case ex: FileNotFoundException => // Handle missing file?case ex: IOException => // Handle other I/O error ?} finally {?f.close()?}
def f(n:Int) = { require(n!=0); 1.0/n } ?def f(n:Int) = { require(n!=0, "n can't be zero"); 1.0/n }?f(0)
// java.lang.IllegalArgumentException: requirement failed:?n can't be zero
require method takes one boolean parameter. If the passed value is true, require will return normally, otherwise, require throu an IllegalArgumentException. require 內含一個bool型參數,如果返回為true,則正常返回;否則 拋出參數非法異常。