lang
Java++:增加的語法 -》純OO;操作符重載凌净;closure泻蚊;使用trait進(jìn)行mixin組合;existential type(_)没卸;抽象類型(type T) class C1[T]{...}秒旋;模式匹配 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??Java--:刪減的語法-》 靜態(tài)成員迁筛;原生數(shù)據(jù)類型;break尉桩、continue贪庙;接口止邮;通配符List, import pkg.*;;原始類型class C1<T> {...}屈扎;enum枚舉
注:existential type——和Java互操作時進(jìn)行對應(yīng),?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調(diào)用Java的方法時鹰晨,會碰到有Scala的保留字止毕,如Thread.yield();?這在Scala中是非法的滓技,專門有個解決辦法,寫成:Thread.`yield`() ??注意:沒有break和continue
這些標(biāo)識在Java中是非法的膝昆,在Scala中是合法的叠必,可以當(dāng)作函數(shù)名使用纬朝,使接口更加DSL:val empty_? = true ? ? ? ??val + = "hello" ? ? ? ? val `yield` = 10 ? ? ?val ** = "power" (經(jīng)常看不懂)?注意:可用但可讀性不好
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對應(yīng)的默認(rèn)值?注意:僅 var可用"_"表示缺省值賦值魂毁。 使用val _ 缺省 會在運(yùn)行時報錯:unbound placeholder parameter
val不可變,相當(dāng)于const/final咬崔,但如果val為數(shù)組或者List刁赦,val的元素可以賦值;val pi = 3. //相當(dāng)于3.0d ;?val pi = 3.f //相當(dāng)于3.0f?提示:向函數(shù)式風(fēng)格推進(jìn)的一個方式甚脉,就是嘗試不用任何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個到多個
使用正則表達(dá)式定義: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的區(qū)別
val:定義時就一次求值完成,保持不變?val f = 10+20 // 30
lazy:定義時不求值,第一次使用時完成求值,保持不變?lazy f = 10+20 //?f // 30
def:定義時不求值,每次使用時都重新求值?(無參,缺省返回值類型的函數(shù)定義)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自動對應(yīng)到Java原始類型书劝,提高運(yùn)行效率购对。Unit對應(yīng)java的void,用asInstanseOf[T]方法來強(qiáng)制轉(zhuǎn)換類型: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統(tǒng)一了原生類型和引用類型。
-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可以轉(zhuǎn)化為List[Char]?在String上做循環(huán)黍图,其實就是對String中的每一個Char做操作,如:?"jamesqiu" max // 'u'?"jamesqiu" min // 'a'?('a' to 'f') map (_.toString*3) // (aaa, bbb, ccc, ddd, eee, fff)
可以表示很大的整數(shù):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) //相當(dāng)于"Hello".toUpperCase
"101".toInt // 101丰滑,無需Integer.parseInt("101"); ??"3.14".toFloat // 3.14f ? ; ??101.toString ?; ?3.14.toString ? ; ? ?轉(zhuǎn)換整個列表: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,用于安全的函數(shù)返回值
Unit:無返回值的函數(shù)的類型栏账,和java的void對應(yīng)
Nil:?長度為0的List
Scala的==很智能,他知道對于數(shù)值類型要調(diào)用Java中的==竖般,ref類型要調(diào)用Java的equals() ?"hello"=="Hello".toLowerCase() ?在java中為false茶鹃,在scala中為true ;?Scala的==總是內(nèi)容對比基本類型Int闭翩,Double,比值,?其他類型?相當(dāng)于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實現(xiàn)了map, flatMap, and filter接口竞漾,允許在'for'循環(huán)里使用它窥翩;
函數(shù)返回值能被統(tǒng)一處理了:
沒有Option的日子 def find(id:Long):Person = ...? 返回Person或者null? 返回null不特殊處理會拋:NullPointerExceptions? 類比:Java的Stringx.split返回null
現(xiàn)在:?def find(id:Long):Option[Person] = ...?返回Some[Person]或者None?返回值直接getOrElse或者列表操作?類比:Java的Stringx.split返回new String[0]
結(jié)論:函數(shù)永遠(yuǎn)不要返回null值寇蚊,如果輸入有問題或者拋異常,返回Option[T]
參數(shù)有效性檢查沒有那么煩人了:沒有Option的日子: def blank(s:String) =if (s==null) false else{s.toList.forall(_.isWhitespace) } ??現(xiàn)在:?def blank(s:String) =Option(s).toList.forall(_.forall(_.isWhitespace))?結(jié)論:盡可能地不要浪費(fèi)代碼去檢測輸入允耿,包裝成Option[T]來統(tǒng)一處理
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結(jié)合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循環(huán),符號∈的象形
=> ? ??List(1,2,3).map(x=> x*x) ??((i:Int)=>i*i)(5) // 25 ? ? ?用于匿名函數(shù) ?也可用在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..=>結(jié)束不用寫break了,_相當(dāng)于default
match可以很簡單地匹配數(shù)據(jù)類型(不需要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?//記錄標(biāo)識,以便能同時對-h和-v做出響應(yīng)
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(使用映射式函數(shù)):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 內(nèi)含一個bool型參數(shù),如果返回為true入宦,則正常返回室琢;否則 拋出參數(shù)非法異常盈滴。