《Scala程序設(shè)計(jì)(Ver.2)》讀書筆記

第一章


  1. 命令行中使用:load命令來加載(編譯并運(yùn)行)文件(腳本文件):scala> :load example.scala
  2. 編譯為字節(jié)碼文件:
    • 腳本:將腳本內(nèi)容封裝入一個(gè)指定的類中晓避,使用>scalac -Xscript MyClass example.scala于是會(huì)生成MyClass.class的文件辈末。
    • 有package批糟、類描述的代碼文件:使用>scalac example.scala城侧。
  3. 對(duì)于生成的字節(jié)碼文件蜘腌,假定文件的包在com.example下包颁,使用>scala -cp . com.example.MyClass來運(yùn)行宗兼。
  4. 如果想要java來編譯生成的scala的字節(jié)碼文件氯檐,需要用到scala-library.jar文件齐遵,假定該文件在C:\Users\Berlin\.sbt\boot\scala-2.10.6\lib下寂玲,則寫為>java -cp .;C:\Users\Berlin\.sbt\boot\scala-2.10.6\lib\scala-library.jar MyClass
  5. val foo定義一個(gè)不可變的量,var foo定義了一個(gè)可變的量梗摇。
  6. 類的定義:
    class Upper {
        def upper(strings: String*): Seq[String] = {
            strings.map((s:String) => s.toUpperCase())
        }
    }
    val up = new Upper
    println(up.upper("Hello", "World!"))
    
    • 定義了名為Upper的類拓哟,其中有名為upper的方法,
    • 方法接受String類型參數(shù)伶授,參數(shù)名為strings断序,個(gè)數(shù)為任意個(gè)(因?yàn)镾tring后有一個(gè)星號(hào)*)。
    • 返回類型為Seq泛型類型(序列)糜烹,類型為String违诗,相當(dāng)于Java語法的Seq<String>
    • class Upper后沒有參數(shù)列表(比如class Upper(name:String,age:Int){ def upper... })疮蹦,因此構(gòu)造方法沒有參數(shù)诸迟,所以不用寫括號(hào),直接寫val up = new Upper愕乎。
  7. 方法定義
    def methodName( parameter1 : Type1,parameter2 : Type2 ) : returnedType = { //...method Body }
    • 返回類型通痴笪可以省略(遞歸時(shí)要寫)
    • 在方法體只有一個(gè)語句時(shí)可以省略花括號(hào)
    • 方法體最后一句表達(dá)式的值就是返回值。
    • 返回空可以寫成...) : Unit = {//......}
  8. 單例對(duì)象
    object Upper {
        def upper(strings: String*) = strings.map(_.toUpperCase())
    }
    println(Upper.upper("Hello", "World!"))
    
    • object關(guān)鍵字定義了一個(gè)名為Upper的單例對(duì)象感论,
    • Scala 運(yùn)行時(shí)只會(huì)創(chuàng)建Upper 的一個(gè)實(shí)例绅项。也就是說,你無法通過new 創(chuàng)建Upper 對(duì)象比肄。就好像Java 使用靜態(tài)類型一樣
    • 形如( foo : Type ) => foo.method()( foo : Type ) => method(a,foo,b,c)可以簡(jiǎn)寫_.method()method(a,_,b,c)
  9. Scala 不支持靜態(tài)類型
  10. 插值字符串:以s表示:println( s"Hello ${ this.name } ")快耿,則變量值會(huì)被替換進(jìn)去湿硝。切記以s為標(biāo)識(shí)
  11. case class:
    • 支持模式匹配润努,多用于模式匹配
    • 必須有參數(shù)列表,就算沒有也要有括號(hào):case class Clazz(){....
    • 參數(shù)列表中的參數(shù)為public示括,并且是val铺浇,即不可變,可以外部訪問
    • case class創(chuàng)建實(shí)例時(shí)可以不用加new(普通class必須加new)
    • 默認(rèn)實(shí)現(xiàn)了toString垛膝、hashCode鳍侣、equals方法
    • 默認(rèn)是可以序列化的,也就是實(shí)現(xiàn)了Serializable 吼拥;
    • 同時(shí)創(chuàng)建了伴生object倚聚,并實(shí)現(xiàn)apply方法
    • 更多參考...
  12. 伴生對(duì)象:case class會(huì)生成與其同名的單例對(duì)象(object),它實(shí)現(xiàn)了apply方法凿可。這個(gè)方法是一個(gè)工廠方法惑折,使用case class生成實(shí)例時(shí)不用new,就是因?yàn)閟cala可以自動(dòng)尋找apply方法產(chǎn)生一個(gè)實(shí)例對(duì)象枯跑。因此惨驶,假設(shè)Point是一個(gè)case class,則這兩句話是等價(jià)的:
    • val p1 = Point.apply(1.0, 2.0)
    • val p2 = Point(1.0, 2.0)
  13. 可以自己定義伴生對(duì)象敛助。任何時(shí)候只要對(duì)象名(object Clazz {...})和類名(class Clazz {...})相同并且定義在同一個(gè)文件中粗卜,這些對(duì)象就能稱作伴生對(duì)象。
    在伴生對(duì)象中可以定義自己的apply纳击,然后使用類名(參數(shù)列表)即可使用
    object Singleton {
        def apply(age:Int,name:String):Unit =
            println(s"your name is ${name}, age is ${age}");
    }
    
    Singleton(name="Amy",age=100);
    
    //輸出:your name ....
    
    但是如果這么寫就會(huì)有問題:
    class CaseClass_{
        def apply(s:Int) ={println("good")}
    }
    CaseClass_(5)
    
    輸出錯(cuò)誤信息:error: not found: value CaseClass_
  14. equals方法:scala的==會(huì)映射為equals方法续扔,即進(jìn)行值比較(包括對(duì)象)。若比較對(duì)象的內(nèi)存地址焕数,則使用eqneobj1 eq obj2
  15. 嵌套導(dǎo)入:
    object Messages { 
        object Exit           // 沒有類體
        object Finished
        case class Response(message: String) 
    }
    class ShapesDrawingActor { 
        import Messages._   //只在這個(gè)類范圍內(nèi)生效:導(dǎo)入Messages對(duì)象內(nèi)容纱昧,可以直接使用,如Exit堡赔,而不用寫全稱Messages.Exit
        def ....
    
  16. 在Scala 中砌些,main 方法必須為對(duì)象方法(object)。(在Java 中加匈,main 方法必須是類靜態(tài)方法:
     object Test{     //而不是 class Test存璃,否則會(huì)提示 CaseClass_.main is not static
          def main(args: Array[String]) = {
                //.......
           }
      }
    

第二章


  1. 變量聲明: val/var name : Type = value

    • 不可變:val array: Array[String] = new Array(5)
    • 可變:var stockPrice: Double = 100.0
      變量聲明的同時(shí)必須立即初始化。(例外:如構(gòu)造函數(shù)的參數(shù)列表:class Person(val name: String, var age: Int)
  2. Range: 支持Range 的類型包括Int雕拼、Long纵东、Float、Double啥寇、Char偎球、BigInt洒扎、BigDecimal

    • 1 to 10 : [1,10]
    • 1 until 10:[1,10)
    • 1 to 10 by 3
    • 10 to 1 by -3
    • 1L to 10L by 3
    • 'a' to 'g' by 3
    • BigDecimal(1.1) to BigDecimal(10.3) by 3.1
  3. 偏函數(shù):在偏函數(shù)中只能使用case 語句(處理那些能與至少一個(gè)case 語句匹配的輸入,輸入?yún)s與所有語句都不匹配衰絮,系統(tǒng)就會(huì)拋出一個(gè)MatchError)袍冷,而整個(gè)函數(shù)必須用花括號(hào)包圍。

    object CaseClass_{
    def main(args: Array[String]) = {
            var func:PartialFunction[Any,String]={   //輸入任意類型猫牡,返回字符串
                case s:String=>    //匹配String胡诗,值賦予s
                    "hello "+s
                case w:Int =>    //匹配Int,值賦予w
                    "This is Int"
                case whatAreYouTalking=>    //任意類型淌友,賦予變量whatAreYouTalking
                    "Nothing" 
            }
            println(func("bbc"));
            println(func(123));
            println(func(3.14));
        }
    }
    

    輸出:

    hello bbc
    This is Int
    Nothing
    

    在偏函數(shù)上調(diào)用isDefinedAt方法可以檢測(cè)某個(gè)實(shí)例是否能被該偏函數(shù)匹配煌恢,返回是布爾值:func.isDefinedAt(3.14f)

  4. copy 方法:copy 方法也是case 類自動(dòng)創(chuàng)建的。copy 方法允許你在創(chuàng)建case 類的新實(shí)例時(shí)只給出與原對(duì)象不同部分的參數(shù)震庭。例如某case class方法的參數(shù)列表有x瑰抵、y兩個(gè)值且都有默認(rèn)值,則調(diào)用copy方法時(shí)只寫 p.copy(y=3.14)器联,從而創(chuàng)建一個(gè)新的實(shí)例二汛,它的y是3.14但是x是默認(rèn)值。

  5. 方法具有多個(gè)參數(shù)列表

    • def draw (offset: Point = Point(0, 0)) (f: String => Unit) = {....} 有兩個(gè)參數(shù)列表
    • 使用方法:draw(Point(1, 2))(str => println("hello")
    • 允許把參數(shù)列表兩邊的圓括號(hào)替換為花括號(hào): draw(Point(1, 2)){str => println("hello")}
    • 使用缺省的參數(shù)拨拓,第一個(gè)圓括號(hào)就不能省略:draw(){str => println("hello")}
    • 請(qǐng)注意區(qū)分函數(shù)體和參數(shù)列表习贫,盡管在scala中它們都可用花括號(hào)包裹。
  6. 注意無論是不是多參數(shù)列表千元,只有為單一參數(shù)時(shí)才能大小括號(hào)混用苫昌,否則只能用小括號(hào):

    scala> def s(a:Int)(b:String,c:Double)={
     | println(a)
     | println(b,c)
     | }
     scala> s{123}{"das",3.14} //因?yàn)榈诙€(gè)列表不是單參數(shù),所以不能用花括號(hào)幸海。
     <console>:1: error: ';' expected but ',' found.
       s{123}{"das",3.14}
                   ^
    

    參考: Scala之小括號(hào)和花括號(hào)(Parentheses & Crurly Braces)

  7. 多參數(shù)列表可以進(jìn)行類型推斷:

    • def m1(a: Int, f : Int => String) = .....祟身,則m1(100, i => s"$i + $i")會(huì)提示i的類型沒有給定
    • def m2(a: Int)(f: Int => String) = ...,則m2(100)(i => s"$i + $i")就米有錯(cuò)物独,Scala可以推斷出i是Int類型袜硫。
  8. 方法的定義還可以嵌套:

    def outer() = {
        def inner() : Int ={ 
            ...
        }
        inner();
    }
    

    內(nèi)部參數(shù)可以屏蔽同名外部參數(shù)

  9. 使用scala.annotation.tailrec的tailrec注解來檢查遞歸函數(shù)是否實(shí)現(xiàn)了尾遞歸,如果沒有則會(huì)拋出異常:

    import scala.annotation.tailrec
    @tailrec
    def method(...) : Type = { ...}
    
  10. 推斷類型信息

    • 在java等靜態(tài)語言中挡篓,要寫:HashMap<Integer, String> intToStringMap = new HashMap<Integer, String>();或者HashMap<Integer, String> intToStringMap = new HashMap<>();
    • 在Scala中只用寫:
      • val intToStringMap: HashMap[Integer, String] = new HashMap
      • val intToStringMap2 = new HashMap[Integer, String] 非顯式類型注解
    • 例如婉陷,
      def report(name:String)={
          val copy = name;   
          // copy沒有寫成 var copy:String =name。因?yàn)榭梢宰詣?dòng)推斷出類型
          println(s"Your name is ${copy}")
      }
      report("Robust") //輸出:Your name is Robust
      
      但是如果寫成
      def report(name:String)={
         var copy :String;  // 或是 var copy官研,即不指定類型秽澳,但是都沒有初始化
         copy = name;   
         println(s"Your name is ${copy}")
      }
      report("Robust") //輸出:Your name is Robust
      
      則會(huì)報(bào)錯(cuò):
      • var copy;error: '=' expected but ';' found.
      • var copy :String;error: only traits and abstract classes can have declared but undefined members
  11. 需要顯式類型注解的情況

    • 在類中抽象聲明時(shí),聲明了可變的var 變量或不可變的val 變量戏羽,但沒有進(jìn)行初始化担神。
    • 所有的方法參數(shù)(如def deposit(amount: Money) = {…})。注意始花,如果寫成def deposit(var amount: Money) = ...def deposit(val amount: Money) = ...就會(huì)報(bào)出兩個(gè)錯(cuò)誤:
      • error: identifier expected but 'var' found.
      • error: only traits and abstract classes can have declared but undefined members
        因此在方法的參數(shù)列表中不要寫val或var
    • 方法的返回值類型妄讯,在以下情況中必須顯式聲明其類型:
      • 明顯地使用了return
      • 遞歸方法
      • 兩個(gè)或多個(gè)方法重載(擁有相同的函數(shù)名)孩锡,其中一個(gè)方法調(diào)用了另一個(gè)重載方法,調(diào)用者需要顯式類型注解亥贸。
      • Scala 推斷出的類型比你期望的類型更為寬泛躬窜,如Any。
  12. Scala中下劃線的用法

  13. _*的用法:設(shè)def joiner(strings: String*): String = {....}函數(shù)joiner是一個(gè)接受變長(zhǎng)參數(shù)的函數(shù)炕置,參數(shù)類型為String荣挨。則現(xiàn)在有一個(gè)列表strings: List[String],為了將其變?yōu)榉指舻淖冮L(zhǎng)參數(shù)從而可以適應(yīng)joiner的參數(shù)列表讹俊,可以使用:joiner ( strings: _*)的語法結(jié)構(gòu)。這個(gè)可以這么來理解:

    • 變量標(biāo)識(shí)符后面的冒號(hào)表示告訴編譯器這個(gè)變量是某種類型
    • 下劃線表示類型卻不是指定的煌抒,而是根據(jù)輸入推斷得出的仍劈。Scala 不允許你寫成strings :String *即使你需要為第一個(gè)joiner 方法指定的輸入類型就是String寡壮。(奇怪)
    • *指示是一個(gè)變長(zhǎng)列表
      所以綜上所述贩疙,它就是告訴編譯器這個(gè)參數(shù)需要由列表類型“拆分”成變長(zhǎng)參數(shù)列表。
  14. 返回類型推斷:最近公共類型况既。假定某方法不指定返回值这溅,其中有一個(gè)if-else結(jié)構(gòu),if中返回List[Int]類型結(jié)果棒仍,而else返回List[String]結(jié)果悲靴,則Scala推斷出的返回值類型就是它們的公共父類型,即List[Any]莫其。

  15. 函數(shù)和過程:在scala中能夠定義函數(shù)癞尚。定義的函數(shù)可以有返回值,也可以沒有返回值乱陡。沒有返回值的叫做過程浇揩,有返回值的叫做函數(shù)。在語法上的區(qū)別是是否有等號(hào)

    • def greeting(name:String){ println(s"Hello ${name}"); 3.14159} 這是一個(gè)過程憨颠,因?yàn)閰?shù)列表和花括號(hào)之間沒有等號(hào)胳徽,所以它返回的是Unit盡管它會(huì)返回一個(gè)浮點(diǎn)數(shù)3.14159爽彤。打印它的結(jié)果是不可預(yù)知的养盗,通常情況會(huì)打印一個(gè)()。例如适篙,println(greeting("David"))會(huì)輸出Hello David以及()爪瓜。
    • def greeting(name:String)={ println(s"Hello ${name}")} 這是一個(gè)函數(shù),盡管類型推斷認(rèn)為它也返回Unit匙瘪,并且println(greeting("David"))輸出結(jié)果和上面相同铆铆。
  16. break 和continue在Scala 中不存在蝶缀。

  17. 若方法中含有某些關(guān)鍵字,則使用單引號(hào)來表示薄货。比如,java.util.Scanner.match翁都,而match是Scala關(guān)鍵字,所以要寫java.util.Scanner.`match`

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末谅猾,一起剝皮案震驚了整個(gè)濱河市柄慰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌税娜,老刑警劉巖坐搔,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異敬矩,居然都是意外死亡概行,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門弧岳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來凳忙,“玉大人,你說我怎么就攤上這事禽炬〗眩” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵腹尖,是天一觀的道長(zhǎng)柳恐。 經(jīng)常有香客問我,道長(zhǎng)热幔,這世上最難降的妖魔是什么胎撤? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮断凶,結(jié)果婚禮上伤提,老公的妹妹穿的比我還像新娘。我一直安慰自己认烁,他們只是感情好肿男,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著却嗡,像睡著了一般舶沛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上窗价,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天如庭,我揣著相機(jī)與錄音,去河邊找鬼撼港。 笑死坪它,一個(gè)胖子當(dāng)著我的面吹牛骤竹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播往毡,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼蒙揣,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了开瞭?” 一聲冷哼從身側(cè)響起懒震,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嗤详,沒想到半個(gè)月后个扰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡葱色,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年递宅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冬筒。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡恐锣,死狀恐怖茅主,靈堂內(nèi)的尸體忽然破棺而出舞痰,到底是詐尸還是另有隱情,我是刑警寧澤诀姚,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布响牛,位于F島的核電站,受9級(jí)特大地震影響赫段,放射性物質(zhì)發(fā)生泄漏呀打。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一糯笙、第九天 我趴在偏房一處隱蔽的房頂上張望贬丛。 院中可真熱鬧,春花似錦给涕、人聲如沸豺憔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽恭应。三九已至,卻和暖如春耘眨,著一層夾襖步出監(jiān)牢的瞬間昼榛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工剔难, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胆屿,地道東北人奥喻。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像莺掠,于是被迫代替她去往敵國(guó)和親衫嵌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容