scala之旅-核心語言特性基礎(二)
本章將介紹scala語言的基礎內容
嘗試在瀏覽器中使用Scala
你可以使用ScalaFiddle在瀏覽器中執行Scala。這是一種簡單、零基礎的方式來實驗Scala程式碼段。
- 訪問網址https://scalafiddle.io.
- 複製
println("Hello, world!")
進左邊的面板
- 點選Run. 在右邊的面板就會顯示輸出
表示式
表示式是可以被計算的語句:
1+1
你可以用 println 對錶達式的結果輸出:
println(1) // 1 println(1 + 1) // 2 println("Hello!") // Hello! println("Hello," + " world!") //Hello, world!
【注:輸出結果:】
1
2
Hello
Hello, world
值
你可以用關鍵字 val 來命名錶達式的結果
val x = 1 + 1 println(x) //2
【注:輸出結果:】
2
像 x 這種用來命名結果的,我們稱之為值。引用值不會重新計算表示式。
值不能被重新定義賦值. 【注:val修飾的變數是被final修飾過了】
x = 3 // 無法編譯通過.
值的型別描述可以被省略,編譯器會自行推斷出來。當然也可以顯式地宣告出來
val x: Int = 1 + 1
注意宣告型別時,Int是跟在命名 x 後的,用一個 : 表示這個值的型別
變數
變數跟值類似,但是變數可以重新賦值定義。你可以通過 var 關鍵字來宣告一個變數
var x = 1 + 1 x = 3 // 這裡因為用var宣告,所以可以編譯通過 . println(x * x) // 9
跟值一樣,變數的型別也可以被省略或者被推斷,也可以被顯式的指定出來
var x: Int = 1 + 1
【注:這裡解釋下 scala是一個靜態語言,靜態語言意味著變數一旦型別定下就不可以改變。雖然變數和值都是可以通過編譯器進行型別推斷的,但是型別是不能被修改的。例如:
var a = 10 //變數a 是Int型別,這是編譯器推斷的結果 a = "hello" //這裡編譯會報錯,因為a的型別已經是Int,再重新賦予字串時就會型別錯誤
】
程式碼塊
你可以通過 {} 包圍的方式來組合表示式。我們稱之為程式碼塊。
該塊的最後一個表示式的結果也是這個程式碼塊的最終結果:
println({ val x = 1 + 1 x + 1 }) // 3
函式
函式是具有引數、並且能傳遞引數值的表示式。
你可以定義一個匿名函式(例如 一個沒有名稱的函式),這個函式的作用是給一個整型的值加1
(x: Int) => x + 1
在 => 左邊是一個引數的列表,右邊則是一個包含引數的表示式
當然你也可以命名這個函式
val addOne = (x: Int) => x + 1 println(addOne(1)) // 2
一個函式可以有多個引數:
val add = (x: Int, y: Int) => x + y println(add(1, 2)) // 3
當然它也可以沒有引數:
val getTheAnswer = () => 42 println(getTheAnswer()) // 42
方法
方法外觀和行為都非常像函式,但是它們之間有一些細微的區別。
方法是通過 def 關鍵字定義, def 後面跟著一個名字,然後緊接著一個引數列表,一個返回結果,和一個程式碼體
def add(x: Int, y: Int): Int = x + y println(add(1, 2)) // 3
注意方法的返回型別宣告是在引數列表後面用一個 : 接起來的
一個方法可以傳遞多個引數列表:
def addThenMultiply(x: Int, y: Int)(multiplier: Int): Int = (x + y) * multiplier println(addThenMultiply(1, 2)(3)) // 9
或者根本就沒有引數列表:
def name: String = System.getProperty("user.name")
println("Hello, " + name + "!")
方法和函式還有一些其他區別,但是就目前為止,你還是可以認為方法就是類似於函式的東西。
方法也可以有多行的表示式:
def getSquareString(input: Double): String = { val square = input * input square.toString } println(getSquareString(2.5)) // 6.25
方法的程式碼體內的最後一行表示式的結果也就是方法的返回結果.(Scala有返回關鍵字,但是用的很少) 【注:函式和方法的都是以最後一個變數或表示式作返回結果,你可以認為就是在最後一行程式碼加隱式的加了一個return】
類
你可以用 class 關鍵字定義一個類,類後面接一個引數列表 就是它的有參構造類
class Greeter(prefix: String, suffix: String) { def greet(name: String): Unit = println(prefix + name + suffix) }
greet 方法的返回結果是 Unit ,這表明這個方法沒有任何返回值。 類似於Java和C中的 void。(有一個小區別是,由於Scala的每個表示式都必須返回值,因此Unit實際上也是一個單例的值,只不過這個值是 空(),不包含任何資訊的值)
val greeter = new Greeter("Hello, ", "!") greeter.greet("Scala developer") // Hello, Scala developer!
我們會在後面的章節對類進行一個深入的講解
Case 類
Scala有一個特殊的類,叫做 case 類。預設的情況下,case類的例項是不可變的,且它們是通過值比較的(區別與普通的類,普通的類是通過引用進行比較的)。這些特性讓case 類在模式匹配中非常的有優勢。
你可以定義case類通過 case class 關鍵字宣告:
case class Point(x: Int, y: Int)
你也可以不用new關鍵字就可以例項化一個case類物件
val point = Point(1, 2) val anotherPoint = Point(1, 2) val yetAnotherPoint = Point(2, 2)
case 類是通過值進行比較的,而不是通過引用
if (point == anotherPoint) { println(point + " and " + anotherPoint + " are the same.") } else { println(point + " and " + anotherPoint + " are different.") } // Point(1,2) and Point(1,2) are the same. if (point == yetAnotherPoint) { println(point + " and " + yetAnotherPoint + " are the same.") } else { println(point + " and " + yetAnotherPoint + " are different.") } // Point(1,2) and Point(2,2) are different.
關於case 類還有很多需要介紹,我們會在後面的章節繼續深入介紹,相信你會愛上它們的
Objects 伴生物件
Objects 伴生物件是它們自己定義的一個單例例項。你可以把它認為是一個類自身攜帶的一個單例
你可以用 object 關鍵字來定一個伴生物件objects
object IdFactory { private var counter = 0 def create(): Int = { counter += 1 counter } }
你可以引用物件的名稱來直接訪問它的內部
val newId: Int = IdFactory.create() println(newId) // 1 val newerId: Int = IdFactory.create() println(newerId) // 2
我們將在後面的章節來詳細介紹它
特性 Traits
特性是一個包含某些屬性和方法的抽象資料型別。在Scala繼承中,一個類只能被允許繼承一個其他類,但是它可以被繼承多個特性。
你可以通過 trait 關鍵字來定義特性:
trait Greeter {
def greet(name: String): Unit
}
特性可以有一個預設的實現:
trait Greeter { def greet(name: String): Unit = println("Hello, " + name + "!") }
你可以使用一個 extends 關鍵字來繼承一個特性,並且用 override 關鍵字來重寫它的實現體
class DefaultGreeter extends Greeter class CustomizableGreeter(prefix: String, postfix: String) extends Greeter { override def greet(name: String): Unit = { println(prefix + name + postfix) } } val greeter = new DefaultGreeter() greeter.greet("Scala developer") // Hello, Scala developer! val customGreeter = new CustomizableGreeter("How are you, ", "?") customGreeter.greet("Scala developer") // How are you, Scala developer?
這裡的DefaultGreeter 只繼承了一個特性,但實際上它可以繼承多個特性。
我們將在後面的章節深入介紹特性
Main 方法
main 方法是Scala程式的入口點。Java虛擬機器也需要一個包含一個String陣列引數的 main 方法。
使用一個 伴生物件object,你可以像如下這樣定義一個main 方法:
object Main { def main(args: Array[String]): Unit = println("Hello, Scala developer!") }