2019年9月3日 星期二

Scala 2.x 一 基本常識、迴圈、Method、類別、Case

scala 是基於 java 的,所以 java 要先安裝好
scala 安裝完並設定環境變數後 (我安裝時已自動加了環境變數),在命令提示字元有 scala 可以用即可
IntelliJ -> File/Settings/Plugins,搜尋 scala 並安裝好重啟 Intellij
新增專案後,在專案按右鍵 Add Framework Support,選中 scala,這樣按右鍵就有新增 scala 的選項了

這系列文章使用的是 2.13.0 版做測試

※main 方法

object ScalaTest {
  def main(args: Array[String]): Unit = {
  println("xxx")
  }
}

※args 為參數名稱

※檔名為 ScalaTest.scala


※基本常識

.Value and Variable:
val 為常數,一開始一定要賦值,和 js 一樣
val i: Int = 1,: Int 是確定它的型態

var 宣告變數如可以改變用這個

沒有前|後置遞增|減
沒有 static
沒有 switch,但有 case



※型態的繼承

Nothing -> Byte、Short、Int、Long、Float、Double、Char、Boolean、Unit -> AnyVal -> Any
Nothing -> Null -> List、Option、CustomClass -> AnyRef(java.lang.Object) -> Any

※ java 的八種型態全有,但 Int 和 Char 取名不同,然後多一種 Unit,相當於 java 的 void

※型態轉換規則

1.Byte -> Short -> Int -> Long -> Float -> Double
2.Char -> Int
3.不可強轉

val x: Int = 123456
val y: Float = x
// val z: Long = y
// val z: Long = (Long)y
val z: Double = y

※註解的兩行會編譯錯譯,沒有什麼強轉的


※宣告陣列

// 不定長度
println(Array(1, 2, 3).apply(0))
println(Array("a", "b", "c").apply(0))

// 固定長度
var arr = new Array[String](3)
println(arr(0))
arr(0) = "s"
println(arr(0))

// 多維陣列
var arr3 = Array.ofDim[String](2, 3, 4) // 內鍵到五維
arr3(0)(0)(0) = "000"
println(arr3(0)(0)(0))
println(arr3.length) // 2
println(arr3(0).length) // 3
println(arr3(0)(0).length) // 4

// 固定範圍陣列
val ints = Array.range(5, 10)
for(n <- ints){
  println(n) // 5-9
}

val ints2 = Array.range(5, 17, 3)
for(n <- ints2){
  println(n) // 5 8 11 14
}


※迴圈

while、do...while、for,只有 for 和 java 不一樣,只有 java 的增強型 for 迴圈,但中間不是 :,是 <-,還多出一種迴圈 叫 until

val value = List(1,2,3)
// for(v <- value){
// for(v <- 1 to 10){
for(v <- 1 until 10){ // 不包含10
  println(v)
}

.多層迴圈

scala 的多層 for 迴圈可以一行就搞定,當然寫多行也是可以

for(i <- 1 to 9; j <- 1 to 9){
  println(i + "x" + j + "=" + i * j)
}


for(i <- 1 to 3; j <- 1 to 3; k <- 1 to 3 if j != 2){
  println(i + "-" + j + "-" + k)
}

※如上上兩層和三層的迴圈,後面還可以加 if


.儲存迴圈的值

var xxx = for{i <- 1 to 10 if i != 3; if i < 8}
  yield i

for(x <- xxx) {
  println(x) // 1 2 4 5 6 7
}


var xxx = for(i <- 1 to 10; j <- 1 to 3 if i != 3; if i < 8)
  yield (i,j)

for(x <- xxx) {
  println(x)
}

※不可以有實體 (花括號)


.中斷與繼續

break 和 continue,但 scala 沒有 continue

var loop = new Breaks;
for(v <- 1 until 10){
  if(v == 7) loop.break()
  println(v)
}


var loop = new Breaks;
for(v <- 1 until 10){
  loop.breakable {
if (v == 7) loop.break()
println(v)
  }
}

※new Breaks 後,break() 就是 break;breakable 就是 continue



※Method

格式為:def 方法名(方法參數): 回傳值 = {內容}

def showNum() = 9
println(showNum()) // 9

def showNum:Int = 9
println(showNum) // 9

def add(x: Int): Int = x + 1
println(add(7)) // 8

def add2(x: Int, y: Int):Int = x + y
println(add2(1, 2)) // 3

def add2(x: Int)(y: Int):Int = x + y
println(add2(1)(2)) // 3

※()可以用多個,但用多個時,呼叫也要用多個



※方法裡的方法


java 不允許方法裡再放方法,但 scala 可以

def accu(start:Int, end: Int): Int = {
if(start >= end) return 0
var vstart = start - 1

def accu2(acc: Int, end: Int): Int = {
  //println("acc=" + acc + ", vstart=" + vstart)
  if (vstart == end)
return acc
  else
vstart += 1
accu2(acc + vstart, end)
}
accu2(0, end)
}
println(accu(0, 10))

※加總的程式


※類別

object ScalaTest {
  def main(args: Array[String]): Unit = {
    val a = new A
    val b = new B()
    val c = new C
    val d1 = new D("k", 1)
    println(d1.toString)
    d1.customMethod(99)

    val d2 = new D("k")
    println(d2.toString)

    val e = new E(value=1)
    println(e.toString)
  }

  class B() {}
  class C
  class D(var key:String, value:Int = 0) {
    override def toString: String = s"($key, $value)"

    def customMethod(xx: Int): Unit = {
      println(xx)
    }
  }
  class E(var key:String="xxx", value:Int) {
    override def toString: String = s"($key, $value)"
  }
}
class A {}

※也有內部類別,類別和建構子整合在一起,如果是空的參數,可以省略圓括號

※建構子可以有預設值,這樣就有 overloading 了

※使用 s"($xxx)" 可取得參數值

※class E,第一個建構子有預設值,如果第一個參數給 null,就真的抓到 null 了

※建構子中,有 val、var 時,new 完才可看見,如果不寫就是 private



※訪問修飾子

public、protected、private
以 java 來對比的話,沒有預設不寫的修飾子
protected 只有子類別可訪問,同包不行,這點和 java 不同

.作用域
可以在修飾子後面用方括號包起一個類別
如 private[.ooo.Xxx] :表示除了 Xxx 這個類別外,其他都是 private 的




※setter/getter

class Xxx {
  private var pid: Int = 0

  def id = pid
  def id_= (id: Int): Unit = {
this.pid = id
  }

  // def setId(id: Int): Unit = {
  //   this.id = id
  // }
  //

  // def getId() :Int = {
  //   this.id
  // }

  private def add(x: Int): Int = x + 1
}

val x = new Xxx()
x.id = 999
println(x.id)

※註解的部分是 java 的寫法,也是可以用

※setter 宣告方法:
1.宣告一個外面看不見的變數 (pid)
2.宣告一個外面看的見的變數 (id),這樣外面才可以用這個名稱,
3.然後再宣告一個方法,是 2 的後面加 _=,在 scala 表示 setter

※getter 就是變數名稱 (pid)

※沒有特別寫修飾子,預設是 public,但這個字不能寫,會編譯錯誤



※case

類似 java 的 switch

def xxx(str: String):Int = str match {
case "a" => 1
case "b" => 2
// case _ => 3
}
println(xxx("c"))

※匹配 _ 就是當什麼都匹配不到時用的,此例會報錯,必須將註解打開

※不需要也不能寫 break


※case class

在 scala 可以將 case 用在 class

case class Animal(id: Int, name: String)

val a1 = Animal(1, "dragon")
val a2 = Animal(2, "dragon")
val a3 = Animal(1, "dragon")
val a4 = new Animal(1, "dragon") // 可省略 new
println(a1 == a2) // false
println(a1 == a3) // true
println(a1 == a4) // true


.迴圈判斷

val list = List(
Animal(1, "pig"),
Animal(2, "dog"),
Animal(3, "chicken")
)

for(l <- list) {
l match {
case Animal(1, "pig") => println("I'm pig")
case Animal(2, "dog") => println("I'm dog")
case _ => println("Who am I")
}
}

沒有留言:

張貼留言