如果你本身是一個OOP Programmer, 透過OOP的概念來進入Scala是一個很好的開始, 尤其當你又是JAVA Programmer, 那麼該是時候來藉由Scala來進化到下一個階段:有生產力且有效率的Program. Scala並非一個全新的語言, 當你遇到學習瓶頸的時候, 可以思考看看這個語法特性在JAVA or其他語言是長怎麼樣, Scala又如何做新的詮釋? 很多東西在Scala表面上看似新的, 但Scala只是基於過去的功能做更進化且更好的應用.
Variable:是變數也全都是物件
在Scala中,一般常見的基本型態都可以使用, ex: Byte, Short, Int, Float, Double, Boolean, and Char這些的在記憶體的Size都跟你所知道的沒有太多差別, 唯一你該知道的是, 在Scala中所有東西都是物件, Scala是包含OOP特性的語言, 也因此就貫徹始終的善用物件, 你會注意到的是所有的基本型態在Scala裡使用第一個字母是大寫, 這跟你在JAVA裡面有所不一樣
//scala code val i : Int = 10上面範例是宣告一個Integer變數, 也是物件, 在JAVA中 Integer是基本型態不是一個物件, 也因此宣告的時候會是 int i = 10; 第一個字母是小寫, 讓你知道他是一個keyword去表示基本型態, 而如果是大寫的話就是物件, 但這些在Scala不會區別了, 基本型態一切都是物件;第一個字母都是大寫
Type Inference:類型推斷
Scala有一個很強的功能就是Type inference, 你不必宣告變數的型態, Scala compiler會自動幫你推斷該變數型態
自動推斷數字型態
//Numeric literal val i = 10 val hexa = 0xFF1C val octa = 023 val l = 1000L val d = 0.0 val f = 0.0f val exponent = 1e30
- 變數 i 就會因為給他數字而被推斷是Int
- Scala在數字型態也可接受多樣化的格式; hexa變數因為你數字前面給0x, 所以被推斷是16進位格式, 最後被存成Int 的65308
- octa因為數字前面是0, 所以被推斷成8進位, 最後會被存成Int 的19
- 要放在Long的物件裡面的話, 就必須在數字最後面加個L, Compiler就會推斷這是一個Long integer
- 小數的浮點運算 : 數字有小數點就會被推斷成Double
- 小數點數字最後加上f, 會被推斷成Float
- Scala也可以判斷科學記數法, 在數字前面加上1e, exponent變數就存成 1.0E30
自動推斷字元型態
//Character literal val capB1 = '\102' val capB2 = 'B' val \u0061\u006e\u0073 = 42 val ? = scala.math.Pi //String literal val bookName = "Scala in \"Action\"" //String interpolation val name = "Nilanjan" val sentence = s"My name $name"
- Scala是用Unicode編碼, 因此可以用Unicode 來表示字元, 因此capB1變數的 \102 會被轉成Unicode的 B, 而capB1也會被推斷是Char
- capB2因為你給他一個字元 'B' , 因此被推斷是Char
- Scala變數名稱也可以用Unicode代碼去表示, 比如\u0061\u006e\u0073變數名稱會轉換成相對應的Unicode
- 任何Unicode符號都可以當作變數名稱, 所以像 ? 也可以被宣告成一個變數
- 字串變數是透過 "" 雙引號來判斷, 如果要在字串中顯示雙引號要用 \ 符號, 可以參照 bookName , bookName 會被判斷是字串, 值是 Scala in "Action"
- Scala字串也有差值功能, 在一個字串裡面插入字串, sentence字串變數裡面就透過$符號來插入name的字串, 最後 sentence字串會是 My name Nilanjan
自動推斷XML格式
val book =Scala比較特殊的地方就是可以解析XML格式的Code, 這是一個很棒的功能, 尤其當你在處理資料型態轉換, 正規化, Web service等等, 會很有幫助, Scala會把你的XML轉換到scala.xml.Elem 物件裡面, 所以book 是scala.xml.Elem型態, 表達的是:Scala in Action Nilanjan Raychaudhuri
book: scala.xml.Elem =Scala不只可以解析XML格式, 還可以允許內插入Scala code 以及變數, 只要透過 curly brace {}:大括號在XML的標籤裡面,Scala in Action Nilanjan Raychaudhuri
val message = "I didn't know xml could be so much useful" val code = “1” val alert =上述code, 就是把message變數放入XML的message標籤, 並且把message標籤的參數priority,設為code變數值, date標籤也放入java.util.Date()物件, 而這一切只是透過 curly brace {}:大括號, 最後輸出結果如下{message} {new java.util.Date()}
alert: scala.xml.Elem =I didn't know xml could be so much fun Fri Feb 19 19:18:08 EST 2010
Defining variables:開始Coding的第一步
在上面的變數介紹和類型推斷, 你已經看過不少變數宣告的例子, 很顯然每一個變數的宣告必然前面都會放 val 或者 var, 這兩個Keyword是你踏入Scala第一個要牢記的特性, 就是變數的性質, 是Mutable(可變動) or Immutable(不可變動)
- val代表的是single assignment variable,表明變數就是一個value, 只有宣告的時候可以給初始value, 往後執行時期都不能再去改變該值(很類似JAVA的 final 變數)
- 相反的, var代表就是variable, 讓你的變數值可以任意更動(就跟你過去Programming的變數一樣)
當你的的程式企圖修改一個 val 變數的時候, 會出現Compile error,
val immutable = 99 immutable = 100就會出現錯誤代碼 :
Keyword :冒號, 用來指定型態
_(placeholder, 底線,佔位自元), 用來當作變數的初始值
在Scala中變數宣告的時候都要給其初始值, 變數宣告後面不能空白著, 如果當你在宣告var Mutable變數時候不知道放甚麼, 可以先放底線 _ 當作Default value
var willKnowLater:String = _上例的的結果是 willKnowLater: String = null, 因為你指定為String型態, 而String的Default value是null, 你可以去試試看其他型態, 看看Default value是甚麼, 唯一你可以宣告變數卻不必給它初始值的地方就是class definition.
Keyword:lazy , 更加善用CPU資源, 真正的動態分配
在Scala預設的情況下, 變數的Value是在宣告時期就計算好的, 可是當你宣告一些變數的值, 它的計算時間是 time-consuming (非常耗時)的, 整個程式就會卡在宣告時期, 程式跑半天才有畫面,lazy val forLater = TimeConsumingOperation() //forLater: Unit = <lazy>forLater變數就是接收非常耗時函式(TimeConsumingOperation)的Result, 因為加上的lazy Keyword, TimeConsumingOperation()還不會執行, 而forLater還沒有拿到真正的Result, 只是給它一個初始<lazy>值, 當你真正存取使用到forLater時候 TimeConsumingOperation才會執行並且拿到Result
var a = 1 //a: Int = 1 lazy val b = a + 1 //b: Int = <lazy> a = 5 //a: Int = 5 println(b) //6在這個例子可以更顯然了解lazy怎麼運作的, 因為變數 b 是 lazy, 所以當宣告時期的值還只是<lazy>, 而往後再改變 a 的值, 然後存取 b 去顯示出來的時候會得到 6, 這是因為 b 的值 a+1是在 a = 5 之後才計算的, 如果變數 b 不是 lazy, 而最後印出來的反而會是 2 , 因為 b 的值 a+1 是在 a=5之前就先計算好了, a 的改變已經來不及影響 b 了
lazy Keyword 只允許給val 變數使用, var要使用的話會出現Compiler error
在Scala中, 每行指令最後都不需要加上 ;分號表示結尾, 這跟以往在其他語言比如JAVA很不一樣, Scala訴求寫得更少, 做得更多, Scala code相對JAVA會少很多, 當然如果你還是要加;分號, Compiler還是會讓你過的
Pattern declaration 樣板模式宣告變數
在變數宣告的左邊, 變數名稱的定義上面, 除了定義一個名稱給變數之外, 也可以用Pattern來定義, 這部分有點複雜, 簡單介紹給一個觀念, 往後會有更仔細的說明val first :: rest = List(1, 2, 3) first: Int = 1 rest: List[Int] = List(2, 3)first :: rest變數就不是一個完整變數名稱, 而是一個List pattern, List是一個Scala immutable物件, 用來表示集合串列, List[String] 就是一系列String物件的串列(跟JAVA List類似), 變數first :: rest 就是該串列的 Pattern, 一個 List 串列可以表示成 頭(Head) + 尾巴(Tail) 的Pattern, Head表示串列的第一個元素, Tail表示除了頭以外剩下來的元素串列, 所以 Pattern first :: rest就可以解析List(1 ,2, 3) 變成Pattern List(1) + List(2, 3), 其中first 就對應到 List(1), rest 對應到 List(2, 3), first 與 rest 中間的::兩個冒號是List 物件的method, 用來表示串接, 表示把 first 與 rest這兩個子 List 串接起來, 這種Pattern 的對應, 在Scala上是一個很強大的功能Pattern match, 每種物件可能都有其 Pattern可以用來解析和應用, 上述的List(1, 2, 3) 用Pattern來對應到變數後, 就可以直接用 first 存取 1, rest 存取 2, 3 ; Pattern match更多的後面會更進一步說明
在Scala接觸到第一個最特別的非 val 變數為主, 儘管還不習慣且不明白到底val 的好處, 還是牢記在心底並試著宣告 val 變數 , 除非有必要才使用var
繼續閱讀 Scala Basic2, 函式
沒有留言:
張貼留言