scala 學習筆記-持續更新中
學習列表:
-
幾乎一切乎都是表達式
scala> 1 + 1 res0: Int = 2
-
複合表達式——{}
花括號用於創建複合表達式,複合表達式的返回值是最後一個表達式
scala> { | println("hello world") | "hi" | } hello world res0: String = hi
-
常量
使用val,不能重複給常量賦值
scala> val value = 100 + 1 value: Int = 101 scala> value = 200// 給常量重複賦值將報錯 <console>:11: error: reassignment to val value = 200 ^
-
變量
使用var,可以修改變量的值
scala> var value = 100 value: Int = 100 scala> value = 200 value: Int = 200
-
類型推斷
scala支持類型推斷,類型聲明置後,編譯器會推斷其類型,會比java更加簡潔
scala> val m: Int = 100// 不建議 m: Int = 100 scala> var n: String = "hi"// 不建議 n: String = hi scala> val m = 100// 推薦 m: Int = 100 scala> var n = "hi"// 推薦 n: String = hi
-
函數
使用def創建函數(與python一樣),需要爲函數參數指定類型簽名,函數返回值類型可以不寫(遞歸函數必須聲明返回值類型),讓編譯器進行類型推斷
scala> def sum(a: Int, b: Int): Int = a + b// 中規中矩的寫法 sum: (a: Int, b: Int)Int scala> sum(2, 3) res8: Int = 5 scala> def fun(x: Int) = x*x// 不聲明返回值類型 fun: (x: Int)Int scala> fun(5) res9: Int = 25 // 使用複合表達式 scala> def mul(x: Int, y: Int) = { | println(x.toString) | println(y.toString) | x * y | } mul: (x: Int, y: Int)Int scala> mul(2, 3) 2 3 res12: Int = 6 // 無返回值的函數可以不用=,代表返回值爲Unit類似java中void scala> def hi() { | println("hi world!") | } hi: ()Unit scala> hi// 無參函數可以不使用括號調用 hi world!
-
匿名函數
使用 =>
scala> (x: Int) => x*x res14: Int => Int = <function1> scala> res14(5) res15: Int = 25
可以將匿名函數進行賦值
scala> val fun = (x: Int) => x*x fun: Int => Int = <function1> scala> fun(3) res27: Int = 9
同樣可以使用{}定義複雜的匿名函數
scala> var m = {x: Int => | println("hi") | val temp = x*x | temp + 1 | } m: Int => Int = <function1> scala> m(4) hi res28: Int = 17
-
部分應用(partially applied function)
你可以使用下劃線“_”(通配符)部分應用一個函數,結果將得到另一個函數。
scala> def add(x: Int, y: Int) = x+y add: (x: Int, y: Int)Int scala> add(4, _:Int) res1: Int => Int = <function1> scala> res1(3) res2: Int = 7
-
柯里化函數(curried)
有時會有這樣的需求:允許別人一會在你的函數上應用一些參數,然後又應用另外的一些參數。
scala> def mul(x: Int)(y:Int) = x*y mul: (x: Int)(y: Int)Int scala> mul(2)_ res3: Int => Int = <function1> scala> res3(5) res4: Int = 10
多參函數柯里化
scala> def mul3(x: Int, y: Int, z: Int) = x*y*z mul3: (x: Int, y: Int, z: Int)Int scala> (mul3 _).curried res8: Int => (Int => (Int => Int)) = <function1> scala> res8(2) res9: Int => (Int => Int) = <function1> scala> res9(3) res10: Int => Int = <function1> scala> res10(4) res11: Int = 24
-
變長參數
向方法傳入任意多個同類型的參數,比如任意多個整數求和
scala> def sum(nums: Int*) = (nums reduceLeft ((x: Int, y: Int) => x+y)) sum: (nums: Int*)Int scala> sum(1,2,3,4,5,6,7,8,9,10) res19: Int = 55
-
參數限定
scala可以使用require進行函數參數限制,類似java assert
scala> def sq(x: Int) = { | require(x >= 0, "input must > 0!") | math.sqrt(x) | } sq: (x: Int)Double scala> sq(2) res0: Double = 1.4142135623730951 scala> sq(-1) java.lang.IllegalArgumentException: requirement failed: input must > 0! at scala.Predef$.require(Predef.scala:219) at .sq(<console>:11) ... 33 elided
-
隱式類型轉換(implicit)
在同一作用域下,自動進行類型的轉換,與該函數名無關,僅與其輸入輸出類型有關
scala> implicit def fun(x: String) = x.toInt fun: (x: String)Int scala> math.max("132", 13) res0: Int = 132
-
閉包(closure)
函數及其執行所需的上下文環境(“An object is data with functions. A closure is a function with data.” — John D. Cook)
scala> def fun() = { | var i = 0 | val lam = () => {i+=1;i} | lam | } fun: ()() => Int scala> val clo = fun() clo: () => Int = <function0> scala> clo() res0: Int = 1 scala> clo() res1: Int = 2 scala> clo() res2: Int = 3
-
傳名參數(call by name,傳值、傳引用之外的另外一種參數傳遞方式)
傳名的參數傳遞使用替換規則。
scala> def callByNameFun(x: => Int) = List(x, x)// =>開頭爲傳名參數 callByNameFun: (x: => Int)List[Int] // 定義高階函數createNum產生一個函數,使用閉包,每調用一次fun(),i自增加1 scala> def createNum() = { | var i = 0 | val fun = { | () => | i += 1 | i | } | fun | } createNum: ()() => Int scala> val f = createNum() f: () => Int = <function0> scala> callByNameFun(f()) res0: List[Int] = List(1, 2) scala> callByNameFun(f()) res1: List[Int] = List(3, 4)
-
尾遞歸
尾遞歸函數返回值爲本身或者結果,同一般的遞歸相比,可被直接轉化爲循環,棧的開銷爲O(1),scala中可以用 @tailrec 檢測定義的函數是否爲尾遞歸
scala> import scala.annotation.tailrec scala> @tailrec def fun(re: Int, index: Int): Int = { | if (index == 0) { | re | } else { | fun(re+index, index - 1) | } | } fun: (re: Int, index: Int)Int scala> fun(0, 100) res0: Int = 5050 scala> fun(0, 100) res1: Int = 5050
-
類
使用class關鍵字
scala> class User { | var name = "bernie" | var age = 23 | def show() = println(name + ":" + age.toString) | } defined class User scala> var user = new User() user: User = User@41112c13
構造函數,構造函數不是特殊的方法,他們是除了類的方法定義之外的代碼。
scala> class Person(pName: String, pAge: Int) { | var name = pName | var age = pAge | def show() = println(name + ":" + age.toString) | } defined class Person // 也可重載構造函數 scala> class Person(pName: String, pAge: Int) { | def this(pName: String) = this(pName, 18) | var name = pName | var age = pAge | } defined class Person
-
抽象類
和java差不多,繼承也使用extends
scala> abstract class AbstractFather { | def fun(x: Int): Int | } defined class AbstractFather
-
特質(trait)
是一組屬性與行爲的組合,特質可以多擴展,在抽象類與特質之間優先選擇特質
scala> trait Fly { | val wing: Int | def fly() = println("I can fly") | } defined trait Fly scala> trait Run { | val leg: Int | def run() = println("I can run") | } defined trait Run scala> class Bird extends Fly with Run { | val wing = 2 | val leg = 2 | def power() = { | fly() | run() | } | } defined class Bird scala> new Bird().power() I can fly I can run
-
單例的語言級別實現——object
Util類就非常適合使用object定義
object Util { def echo() = println("Hello World!") }
-
伴生對象與伴生類
名字相同的class與object,放在同一個文件下定義,能夠訪問彼此的私有成員
-
泛型
使用中括號,類和方法都可以是泛型的
scala> class Gen[T] { | def show(x: T) = x.toString + "$" | } defined class Gen scala> val gen = new Gen[Int] gen: Gen[Int] = Gen@3a44ebcb scala> gen.show(100) res11: String = 100$ scala> def genFun[T](x: T) = x.toString + "&" genFun: [T](x: T)String scala> genFun(100) res13: String = 100&
-
語法糖 apply update
爲了方便你使用類,scala提供了apply 與 update語法糖
scala> object Arr { | val arr = Array(0,1,2,3,4,5) | def apply(i: Int) = arr(i) | def update(i: Int, value: Int) = {arr(i) = value} | } defined object Arr scala> Arr(1) res38: Int = 1 scala> Arr(1) = 100 scala> Arr.arr res40: Array[Int] = Array(0, 100, 2, 3, 4, 5)
其實 Array 取值與更新就是實現了這兩個方法
-
函數與對象de邊界
函數可以看作一堆特性的集合(Funtion0 -> Funtion22),apply語法糖有助於統一對象和函數式編程的二重性,你可以傳遞類,並把它們當做函數使用,而函數本質上是類的實例
scala> object Fun extends Function1[Int, Int] { | def apply(x: Int) = x*x | } defined object Fun scala> Fun(3) res50: Int = 9
-
模式匹配
感覺像java中switch case,但功能更加強大
scala> val m = 1 m: Int = 1 scala> m match { | case 1 => 100 | case 2 => 200 | case _ => 300 | } res25: Int = 100
-
異常
異常也是表達式
scala> val re = try { | 1/0 | "oh yeah" | } catch { | case e: Exception => println("error happen") | "oh no" | } finally { | println("turn me") | } error happen turn me re: String = oh no
-
集合
List(列表)、Set(集)、Tuple(元組)、Map(映射)、Option(選項)Tuple
元組是在不使用類的前提下,將元素組合起來形成簡單的邏輯集合,讀取方式使用下標,從1開始,可以使用->創建2元組
scala> val tuple = ("hi", "he", "ha", 12, 'a') tuple: (String, String, String, Int, Char) = (hi,he,ha,12,a) scala> tuple._1 res36: String = hi scala> 1 -> 2 res63: (Int, Int) = (1,2)
Map
scala> Map(1 -> "one", 2 -> "two") res0: scala.collection.immutable.Map[Int,String] = Map(1 -> one, 2 -> two) scala> Map((1, "one"), (2, "two")) res1: scala.collection.immutable.Map[Int,String] = Map(1 -> one, 2 -> two)
Option
表示可能包含值的容器,有Some與None兩個子類,特徵接口如下
trait Option[T] { def isDefined: Boolean def get: T def getOrElse(t: T): T }
scala> val map = Map(1 -> "one", 2 -> "two") map: scala.collection.immutable.Map[Int,String] = Map(1 -> one, 2 -> two) scala> map.get(1) res2: Option[String] = Some(one) scala> map.get(3) res3: Option[String] = None scala> res2.get res4: String = one scala> res3.get java.util.NoSuchElementException: None.get at scala.None$.get(Option.scala:347) at scala.None$.get(Option.scala:345) ... 33 elided scala> res3.isDefined res6: Boolean = false scala> res3.getOrElse("three") res7: String = three
-
集合操作符(操作符即函數)
map、foreach
map將產生一個新的集合,foreach無返回值,一般僅作遍歷使用,取它的副作用
scala> (1 to 10) map (_ * 2) res21: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20) scala> (1 to 10) foreach (println(_)) 1 2 3 4 5 6 7 8 9 10
reduceLeft、reduceRight(將集合進行函數計算,得到結果)
scala> (1 to 10) reduceLeft ((m: Int, n: Int) => m+n) res42: Int = 55 scala> (1 to 10) reduceRight ((m: Int, n: Int) => m+n) res43: Int = 55
filter(白名單過濾)、partition(分割)
fliter將符合條件的元素產生一個集合返回,partition將其分隔成滿足與不滿足條件的兩元組
scala> (1 to 10) filter (_%2 == 0) res24: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10) scala> (1 to 10) partition (_%2 == 0) res25: (scala.collection.immutable.IndexedSeq[Int], scala.collection.immutable.IndexedSeq[Int]) = (Vector(2, 4, 6, 8, 10),Vector(1, 3, 5, 7, 9)) scala> res25._1 res26: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10) scala> res25._2 res27: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 3, 5, 7, 9)
find、exists、count
find返回符合條件的第一個選項 Option,exists返回Boolean值,count返回滿足條件的個數Int
scala> (1 to 10) find (_%2==0) res30: Option[Int] = Some(2) scala> (1 to 10) exists (_%2==0) res50: Boolean = true scala> (1 to 10) count (_ %2 ==0) res57: Int = 5
zip
顧名思義就是像拉鍊一樣彼此咬合生成新的集合,長短不一的時候以短爲準
scala> Array(1, 2, 3) zip List("a", "b", "c", "d") res53: Array[(Int, String)] = Array((1,a), (2,b), (3,c))