《快學(xué) Scala》 學(xué)習(xí)筆記 - Chapter 2

條件表達式

  • scala的表達式是有返回值的贴硫,和erlang一樣,語句的最后一個表達式就是返回值

  • 可以使用 val s = if (x>0) 1 else -1 的方式聲明變量,此處s 為 Int 類型

    • 也可以用 if (x>0) s=1 else s=-1 但前提是先要通過var 聲明 s, 也就是說s就不能是常量了
  • val s=if(x>0) “asdfadf” else -1 的表達式中英遭,s的類型為Any间护,因為兩個表達式的值類型是不相同的,即混合類型挖诸,那么只能是他們的公共超類Any了

  • if (x>0) 1 則等同于 if (x>0) 1 else ()

    • () 等同于 java中的void

    • () 在scala 中的值為Unit汁尺,表示“無值”的值

  • scala終端里需要注意else的換行問題

    if (x > 0) 1  
    else if ( x == 0 ) 0 else -1  
    

    需要寫成

    if (x > 0) { 1  
    } else if ( x == 0 ) 0 else -1
    
    • 在編譯器中編譯時是無需顧慮這個問題的

    • 可以通過:paste 模式將代碼粘貼進去后統(tǒng)一解析執(zhí)行,這樣scala終端就不會近視了

語句終止

  • 正常多行時不需要分號税灌,單行有多個表達式時需要分號

    • 但是如果不習(xí)慣不使用均函,則可以用,沒什么壞處
  • s=s0+(v-v0)t+ // +告訴解析器這里不是語句的末尾
    0.5
    (a-a0)tt

    • 這里跟GO很像菱涤,符號放到最后苞也,而不是在新一行的開始
  • scala推薦左括號在表達式結(jié)尾,而不是新一行的開始

塊表達式和賦值

  • Scala的結(jié)果也是一個表達式粘秆,和其他語言不同如迟,{}的最后一個表達式就是這個塊表達式的值,因此可以使用塊表達式初始化一個值攻走,此特性和Erlang相同

    • val distance = { val dx=x0; val dy=y-y0; sqrt(dxdx+dydy**) }
  • Scala的負值動作是沒有值的殷勘,嚴(yán)格來講他的值是Unit

    • 比如 { r=r * n; n -= 1 } 的值是 Unit

    • 不要 x=y=1, 因為 y=1的值是()

輸入和輸出

  • print

  • println

  • printf

  • readInt

  • readDouble

  • readByte

  • readShort

  • readLong

  • readFloat

  • readBoolean

  • readChar

  • readLine

    • readLine(“Your name:”)

循環(huán)

  • while(n>0) {}

  • for(i < -1 to n) {}

    • 語法結(jié)構(gòu)可以理解為: for ( i <- 表達式)

    • 1 to n 代表的是1.to(n), 即生成了1 到 n的數(shù)組

    • <- 代表將后面的表達式的值逐一負值到i,但是這里取決于表達式的類型昔搂,這里是一個Range類型

    • 如果期望表達式的范圍是0到n-1 則可以使用 for( i <- until s.length) {}

    • for (ch <- “hello”)

      • 該表達式將字符循環(huán)負值給了ch
  • scala沒有break和continue

    • 一. 使用Boolean型的控制變量

    • 二. 使用嵌套函數(shù) — 你可以從函數(shù)中return

    • 三. 使用 Breaks 對象中的 break 方法

       import scala.util.control.Breaks._  
          
        breakable {  
          for (...) {  
              if (...) break; // 退出breakable塊  
              ...  
          }  
        }
      
      • 這種實現(xiàn)其實是在 break 這個語句拋出了一個異常玲销,然后 breakable 塊捕獲異常來實現(xiàn)的

      • 如果對性能要求很高的,應(yīng)該盡量避免使用這套機制

高級for循環(huán)和for推導(dǎo)式

  • 通用表達式

    • for (變量1 <- 表達式1 [保護語句1]; [變量定義]…; 變量2 <- 表達式2 [保護語句2]) [yield 表達式]

      • 保護語句格式: if xxxx,

      • 是一個以if 開頭的Boolean 表達式

    • for { 變量1 <- 表達式1 [保護語句1]
      [變量定義]
      ...
      變量2 <- 表達式2 [保護語句2] } [yield 表達式]

      • 可以使用圓括號摘符,分號可以修改為換行
  • 例子

     for(i <- 1 to 3; j <- 1 to 3 if i != j ) print ( ... )
    

    等同于Go語言的

     for i := 0; i < 3; i++ {  
        for j := 0; j < 3; j++ {  
            if i != j {  
                fmt.Print(...)  
            }  
        }  
      }
    
    for (i <- 1 to 3; from = 4 - i; j <- from to 3) print(...)
    

    上面在for中定義了變量

    for (i <- 1 to 10) yield i % 3
    

    yield表達式贤斜,將生成結(jié)果:Vector(1,2,0,1,2,0,1,2,0,1)

     for { i <- 1 to 3  
        from = 4 - i  
        j <- from to 3 }
    

函數(shù)

  • Scala除了方法還支持函數(shù),方法對對象進行操作逛裤,函數(shù)不是

  • def abs(x: Double) = if ( x >= 0) x else -x

    • 必須給出所有參數(shù)的類型

    • 如果函數(shù)比較復(fù)雜瘩绒,則可以使用代碼塊{}, 將代碼放到代碼塊里即可

    • 返回參數(shù)

      • 如果是非遞歸函數(shù)

        • 不需要給出返回類型,Scala編譯器可以通過=符號右側(cè)的表達式的類型推斷出返回類型
      • 如果是遞歸函數(shù)

        def fac(n: Int): **Int** = if (n <=0) 1 else n * fac(n-1)
        

默認參數(shù)和帶名參數(shù)

  • 定義

    • 我們在調(diào)用某些函數(shù)時并不顯示的給出所有的參數(shù)值锁荔,對于這些函數(shù)我們可以使用默認參數(shù)

    • 傳入的參數(shù)如果不帶名字蝙砌,則會按順序?qū)?yīng)到默認參數(shù)里

    • 有時候可以我們只想修改特定的默認參數(shù)择克,而這個參數(shù)又在其他的默認參數(shù)后面祠饺,因此我們需要使用帶名參數(shù)的方法來傳入值

  • 例子

    def decorate(str: String, left: String = "[", right: String = "]") = left + str + right
    

    left參數(shù)和right參數(shù)均有默認值道偷,在調(diào)用的時候如果無特殊需求,則不需要傳入值
    帶名參數(shù)的調(diào)用方法

    def decorate("Hello", right = "]<<<")
    

變長參數(shù)

  • def sum(args: Int*) = {}

    • 調(diào)用方法

      • val s = sum(1, 4, 9, 16)

      • val s = sum(1, 4, 9, 16, 25, 100)

  • 可以傳入任意數(shù)量的參數(shù)

  • 錯誤的使用方法

    • 例一

      • 錯誤

        • val s = sum(1 to 5)
      • 正確

        • val s = sum(1 to 5: _*)

          • 后面的 :_* 的作用類似Golang的

            • sum(numbers …)
  • 注意

    • 當(dāng)你調(diào)用變長參數(shù)且參數(shù)類型為Object的Java方法時并巍,你需要手工對基本類型進行轉(zhuǎn)換

      • 例如

        • Java方法

          • MessageFormat public static String format(String pattern, Object... arguments)

            • 此處為Java的方法懊渡,且變參的類型為Object
        • 調(diào)用

          • var str = MessageFormat.format("The answer to {0} is {1}", "everything", 42.asInstanceOf[AnyRef])

          • 由于42是基本類型剃执,因此需要手動轉(zhuǎn)換到 Scala 的 AnyRef 上肾档,AnyRef 等同于 Java 的 Object

過程

  • 定義

    • 如果函數(shù)體包含在花括號當(dāng)中怒见,但沒有前面的 = 號遣耍, 那么返回類型就是Unit炮车,這樣的函數(shù)被稱為 (procedure)

    • 過程不返回值示血,我們調(diào)用它僅僅是為了他的副作用

  • 例子

    • 我們只是想在屏幕上輸出一段文字

      • def box(s: String) { … }

      • 大家仔細看难审,這里是沒有等號的,沒有寫成 def box(s: String) = { … }

  • 習(xí)慣性問題

    • def box(s: String): Unit = { … }

    • 建議大家總是顯式的聲明Unit返回類型

懶值

  • 定義

    • 當(dāng)val被聲明為lazy時麸拄,他的初始化將被推遲拢切,直到我們首次對他取值
  • 例子

    lazy val words = scala.io.Source.fromFile("/usr/share/dict/words").mkString
    

    當(dāng)我們第一次訪問的時候淮椰,這個文件的內(nèi)容才會被讀取,然后復(fù)制給 val

  • 對比說明

    val words = scala.io.Source.fromFile("/usr/share/dict/words").mkString //在words被定義時即被取值
    lazy val words = scala.io.Source.fromFile("/usr/share/dict/words").mkString //在words被第一次使用時取值
    def words = scala.io.Source.fromFile("/usr/share/dict/words").mkString //words函數(shù)每次被調(diào)用時取值
    
  • 其他說明

    • lazy 特性并不是沒有額外開銷泻拦,我們每次訪問都會有一個方法被調(diào)用争拐,而這個方法將會以線程安全的方式檢查該值是否被初始化過
    • 有點像Golang里的sync.Once

異常

  • 說明

    • 受檢異常

      • scala中無java里的受檢異常特性架曹,即在函數(shù)定義的時候就要指出本函數(shù)將會拋出什么異常绑雄,如果代碼里拋出了未在定義里事先列出的異常夹抗,則在編譯時會報錯

      • scala的設(shè)計者決定不支持此特性漠烧,因為在編譯期間做徹底的檢查也并不總是好事

  • 表達式

    • throw 表達式有特殊的類型 Nothing

      • 作用

        • if/else

          • if (x > 0) { sqrt (x)
            } else throw new IllegalArgumentException("x should not be negative")

            • 當(dāng) x > 0 時返回的值是Double

            • 當(dāng) x <=0 時拋出異常已脓,既 Nothing 類型

            • 因此該 if/else 表達式的類型是 Double

  • 捕獲異常

    • 語法

      • try { … } catch { … }

      • try { … } finally { … }

      • 作用和異常的拋出規(guī)則類似度液,如果finally 里出了異常,則會覆蓋之前的異常

    • 例子

       try {  
          process(new URL("http://xxxx.com/yyy.gif"))  
        } catch {  
          case _: MalformedURLException => println("Bad URL:" + url)  
          case ex: IOException => ex.printStackTrace()  
        }
      
      • catch 采用的是模式匹配已慢,此例子會將拋出的異常從上到下佑惠,依次對比異常類型膜楷,如果能匹配上則執(zhí)行 => 后面的語句

      • 模式匹配部分類似Go的類型選擇

       select v:=Exception.(type) {  
          case MalformedURLException:{  
              println("Bad URL:" + url)  
          }  
          case IOException:{  
              v.printStackTrace()  
          }  
        }
      

練習(xí)

  • 第一題

    def signum(v: Int): Int = {  
        if(v > 0 ){  
            1  
        } else if( v == 0 ){  
            0  
        } else {  
            -1  
        }  
      }
    
  • 第二題

    • 是 Unit赌厅,代表空
  • 第三題

    • var x=()

      • scala賦值動作本身是沒有值的轿塔,即賦值動作的結(jié)果為Unit,因此 x=y=1, 他的第一步動作是 y=1, 得到 Unit 類型洽议,如果x為Int類型則會報錯亚兄,因此x應(yīng)該為Unit類型
  • 第四題

    for( i<-1 to 10; j=10-i+1) System.out.println(j)
    
  • 第五題

    def countdown(n: Int):Unit = {  
        for( i<-1 to n; j=n-i+1)   
            System.out.println(j)  
      }
    
  • 第六題

    var value:Long = 1  
     for(char<- "Hello") value*=char  
     System.out.println(value)
    
    • 一開始做題時审胚,書上的Hello值為 9415087488, 而我算出來是 825152896膳叨,后來發(fā)現(xiàn)如果 var value = 1 如果不寫類型則是Int型菲嘴,因此是存儲不下的汰翠,要聲明為Long才行

    • 此處比較坑爹的是复唤,scala 的解釋器,直接帶入 72101108108111 后算出來的值也是錯的, 還是erlang智能

      • scala> 72101108108111
        res2: Int = 825152896

      • Eshell V8.2 (abort with ^G)
        1> 72101108108111.
        9415087488

  • 第七題

    "Hello".foldLeft(1L)(_ * _.toInt)
    
  • 第八題

    def product(s: String):Long = {  
        s.foldLeft(1L)(_ * _.toInt)  
      }
    
  • 第九題

    def product(s: String,seq: Int = 0, value: Long = 1L):Long = {  
        if(seq>=s.length)  
            value  
        else  
            product(s, seq+1, value*s(seq))  
      }
    
  • 第十題

    def calc(x:Long, n:Long):Long = {  
        if(n>0){  
            if(n % 2 == 0L){  
                var y=calc(x,n/2)  
                y*y  
            } else {  
                x*calc(x,n-1)  
            }  
        } else if(n==0){  
            1  
        } else{  
            1/calc(x,-n)  
        }  
      }
    
《快學(xué) Scala》 學(xué)習(xí)筆記 第二章.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市好爬,隨后出現(xiàn)的幾起案子存炮,更是在濱河造成了極大的恐慌型豁,老刑警劉巖迎变,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衣形,死亡現(xiàn)場離奇詭異姿鸿,居然都是意外死亡苛预,警方通過查閱死者的電腦和手機热某,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門昔馋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來秘遏,“玉大人嘉竟,你說我怎么就攤上這事舍扰。” “怎么了审丘?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵滩报,是天一觀的道長脓钾。 經(jīng)常有香客問我桩警,道長,這世上最難降的妖魔是什么握截? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任谨胞,我火速辦了婚禮胯努,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蒲讯。我一直安慰自己灰署,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著约巷,像睡著了一般独郎。 火紅的嫁衣襯著肌膚如雪氓癌。 梳的紋絲不亂的頭發(fā)上贫橙,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天卢肃,我揣著相機與錄音,去河邊找鬼尤蒿。 笑死腰池,一個胖子當(dāng)著我的面吹牛忙芒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播奏属,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼拍皮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了咆耿?” 一聲冷哼從身側(cè)響起萨螺,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤慰技,失蹤者是張志新(化名)和其女友劉穎组砚,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體艾帐,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡柒爸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年捎稚,在試婚紗的時候發(fā)現(xiàn)自己被綠了求橄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡腥泥,死狀恐怖蛔外,靈堂內(nèi)的尸體忽然破棺而出溯乒,到底是詐尸還是另有隱情,我是刑警寧澤矛纹,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布或南,位于F島的核電站,受9級特大地震影響采够,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜权她,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一隅要、第九天 我趴在偏房一處隱蔽的房頂上張望步清。 院中可真熱鬧,春花似錦尼啡、人聲如沸询微。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽斩个。三九已至,卻和暖如春做个,著一層夾襖步出監(jiān)牢的瞬間居暖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工太闺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留省骂,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓怠惶,卻偏偏與公主長得像甚疟,于是被迫代替她去往敵國和親逃延。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,933評論 2 355

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