Scala(一)資料型別

weixin_50034171發表於2020-12-18

Scala簡介

Scala 是一種基於 JVM 的多正規化程式語言,這裡的正規化可以理解為一種程式設計 風格,比如物件導向程式設計就是一種正規化。常見正規化包括:程式導向、物件導向、 泛型以及函數語言程式設計。

一、Scala特點

1.1 靜態型別

  1. Scala的變數宣告後不允許改變型別,換句話說所有的變數和表示式在編譯時就已經完全確定。這一點和Java是一樣的。
  2. 可以增強IDE的型別感知能力,適大型複雜系統開發
    感知就是在使用的時候,就能夠去獲取它的型別
  3. 可讀性好,可以宣告時指定型別,且使用前必須確定型別

1.2 強型別

Scala是強型別語言,一個變數被指定了某個人資料型別,如果不經過強制轉換,name它就永遠是這個資料型別,也就是說不允許隱式型別轉換。意味著 Scala 是型別安全的語言,這點和 Java 也相同,但 Scala 在宣告變數時一般無需顯示指 定型別,Scala 編譯器會自動推斷出型別

       Scala沒有提供Java中的強制型別轉換,取代方法有:
       ①、物件名.asInstanceOf[XXX]
       ②、物件名.toXXX 方法
       ③、隱式轉換(implicit 關鍵字)

1.3 物件導向程式設計(OOP)

Scala 中一切值都是物件,可以說 Scala 比 Java OOP 更純粹。比如,Java 中類 物件(包含靜態欄位和方法)便不是純粹的物件,因為類是一個抽象的概念,對 象是類的例項,是一個具體的概念。所以 Scala 中去除了 static 關鍵字,使用一 種特殊的物件來模擬類物件(伴生物件),使得類的所有靜態內容都可以放置在 它的伴生物件中宣告和呼叫。

二、伴生物件

伴生物件

package one

// 建構函式建立:變數在前,型別在後,自動對映到類裡變成屬性
class Scala_Basic(name:String,age:Int){


  // 方法   變數寫在類裡
  def show():Unit={
    println(s"my name is $name, I'm $age")   // 格式化
  }
}

// 伴生物件(有同名類)
object Scala_Basic {
  def main(args: Array[String]): Unit = {
  // 為了把常量區分開,放在Object中,也體現了動靜分離

    // 建立變數的方式
    var a = new Test("henrry",18)
    a.show()    // 呼叫方法
  }
}

=>  my name is henrry, I'm 18

三、Scala關鍵字

Java 與 Scala 關鍵字對比:

在這裡插入圖片描述

四、Scala變數和常量

val:定義常量(value)
var:定義變數(variable)
區別:val定義的引數是,不能被再次賦值,而var定義的引數可以被再次賦值。一般不嚴格說明時,變數和常量也統稱為變數。變數是可變變數,而常量是 不可變變數。

示例程式碼:
var val

package one

object Review {


  def main(args: Array[String]): Unit = {

    val a = 18
    println(a)
    var b = 10
    println(b)

    println("--------")
    //這裡如果寫上a=10重新賦值會直接報錯,執行不了
    //a=10 這裡是寫寫不了的,直接會報錯  
    println(a)
    b = 20
    println(b)
  }
}

可以看出val定義的常量a不能被改變,而var定義的變數b重新賦值後值改變了
在這裡插入圖片描述
變數的建立方式
在scala中,數值型別為一類型別(包括八大型別)

// 可以不指定型別,但是一定要賦值
var a = 1
var b:Int = 2

// 正確宣告變數的方式
    var a = 1
    var b:Int = 2
    var c:String = "henrry"
    var g:Char = '男'
    var s:Double = 80.0
    var d:Int = _     // 沒有值得時候可以給個下劃線:_
	
	val e:Int = _   // 這個時候就會報錯,常量必須初始化

五、Scala資料型別

在這裡插入圖片描述

  1. 整體上分為兩類:值型別(AnyVal)引用型別(AnyRef),超級父類為Any超級子類為Nothing
  2. 值型別和Java八大基本型別一致(byte、short、int、long、float、double、char、boolean),注意在Scala中所有型別首字母都大寫,還有一個Unit型別,類似於Java中的void,除 了 scala.Unit 和 scala.Boolean 外其餘都是數字型別。
  3. 所有的非值型別都是引用型別,,如果 Scala 執行中 Java 環境中,AnyRef 相當於 java.lang.Object。特別地,Scala 中的 String 型別等同於 java.lang.String。
  4. 值型別:直接儲存值,在棧上儲存其值。
  5. 引用型別:儲存對其值得引用,在棧上儲存地址,在堆上儲存值。
  6. ==是值比較,eq(b)為地址比較

5.1 Unit

Unit 代表沒有任何意義的值型別,他是 AnyVal 的子型別,僅有一個例項對 象“()”,叫做無用佔位符,類似於 Java 中的 void 型別。

結構圖
在這裡插入圖片描述

一般來說用map較多
在這裡插入圖片描述

package two

object Test {
  def main(args: Array[String]): Unit = {

    var map = Map("henrry" -> 18, "areiel" -> 20, "pola" -> 14)
    map.keys.foreach(println)
  }
}


=> henrry
   areiel
   pola

陣列

package two

object Test {
  def main(args: Array[String]): Unit = {

    var arr = Array(11,2,33,42,14)
    // 模擬陣列下標,用下標做一個陣列
    var ixArr = Range.apply(0,arr.length)
    arr.foreach(x=>print(s"$x\t"))
    println()
    ixArr.foreach(x=>print(s"$x\t"))
  }
}
=>輸出結果
11	2	33	42	14	
0	1	2	3	4	

六、Scala字串插值(拼接)

Scala 為我們提供了三種字串插值的方式,分別是 s, f 和 raw。其本質都 是定義在 StringContext 中的方法
# s 利用之後學習的隱式轉換實現

// $符號可以理解為引用值
val name = "henrry"
println(s"my name is $name")
=> my name is henrry

println(s"1 and 1 eq ${1+1}")
=> 1 and 1 eq 2

或者可以這麼寫,宣告瞭變數型別(可寫可不寫)
在Scala中宣告變數和常量不一定要指明資料型別,在沒有指明資料型別的情況下,其資料型別是通過變數或常量的初始值推斷出來的。但是一定要賦初值
var x:Int = 2
println(x)
=> 2

# f 簡單格式化

var name = "henrry";var age = 19;var score=88.123;var gender = '男'
println(f"name=$name%s,age=$age%d,score=$score%.2f,gender=$gender%c")
=> name=henrry,age=19,score=88.12,gender=

# raw 即所見所得,不轉義

println(s"a\tb\nc\td")
println("------")
println(raw"a\tb\nc\td")
=> a	b
   c	d
   ------
   a\tb\nc\td

④、模式匹配

var score = 88
var  rst = score.match {
// i就是score,是隱式引數傳進來的
	case i if i>=80 =>"A"
	case i if i>=70 =>"B"
	case i if i>=60 =>"C"
	case i =>"D"     // 相當於default
println(rst)
}

=> 輸出結果 A

字串

var line:String = """"""

var s = 'Abc     // 符號變數
println(s.isInstanceOf[scala.Symbol])
=>true

Null

  1. 型別Null只有一個物件(Java中null不是物件)
  2. 所有引用型別的子類

Nothing

  1. 所有型別子類,也是Null的子類

Unit

  1. 無意義的值型別
  2. 類似於Java中的void
  3. 在scala中有返回值(),scala中一切表示式都有值

七、函式的定義

  1. 函式的定義以def開始,然後是函式名,類似於 def main
  2. 跟著的是括號裡使用逗號分隔的引數型別鍵值對,類似x:Int,y:Int
  3. 下面的程式碼表示maxInt函式帶有兩個引數:x和y,都是Int型別,在函式列表後,會使用"返回值型別="的形式宣告函式的返回值型別,我的理解是,一切函式都是值,最後的肯定是一個值,如果需要返回值,則需要用返回型別接收確認返回值。

定義格式:

def functionName ([引數列表]) : [return type] = {
   function body
}
def maxInt(x:Int) = {
	if(x > y) x else y
}

// 呼叫函式
val m = maxInt(6,9)
println(m)
=> 9

函式
函式有23種,由trait定義
在這裡插入圖片描述

package one

object Process2 {

// 簡潔的寫函式
  val func = (x: Int, y: Int) => {
    x + y
    // 最後一句話是什麼,返回值就是什麼,沒有return
  }

// 完整的去寫一個函式
val fun2 = new Function2[Int, Double, Double] {   // 泛型 ,輸出型別為Double型

    override def apply(v1: Int, v2: Double): Double = v1 + v2
  }


  def main(args: Array[String]): Unit = {
		  println(func(1,2))
		  println(fun2(1,2))
  }
}
=>   輸出都為3

型別轉換
Boolean a = obj.instanceOf[Xxx]
Xxx a = Obj.asInstanceOf[Xxx]
obj.toXxx
隱式轉換(implicit Xxx)

package one

object Process2 {

 
  }

  def main(args: Array[String]): Unit = {
    var a : String = "henrry"
    println(a.isInstanceOf[String])  // isInstance:判斷是不是指定型別
=>返回true

	println(a.isInstanceOf[Int])
=>返回false

// 嘗試轉換型別
var a : String = "henrry"
println(a.isInstanceOf[String])
if(a.asInstanceOf[Boolean]){
	println("ok")
}
//這裡執行會直接報錯,不給轉,也因此證明了scala是強型別
  }

// 建立一個陣列
    var arr:Array[Int] = Array(1,5,3,2)
    println(arr.toList)
=>  List(1, 5, 3, 2)
	
	println(arr.toString)
=>  [I@6bdf28bb

	println(arr.toSet)
=>	Set(1, 5, 3, 2)
		
// 萬物皆可to,直接轉換	


}

建立一個函式
一切函式都為值
可以將函式作為引數和返回值

object Process2 {
	
  val fun2 = new Function2[Int, Double, Double] {

    override def apply(v1: Int, v2: Double): Double = v1 + v2
  }


def main(args: Array[String]): Unit = {
		// 定義一個方法
		def add(x:Doubele,y:Int):Double = {
		println(s"$x + $y = ${x+y}")
			x + y	
}

	println(add(fun2(1,2)),3)  先呼叫fun2的方法,得到一個結果,再將這個結果作為add方法的輸入最終得到一個結果
=>   輸出6.0  
3.0 + 3 = 6.0
6.0

// 驗證了一切函式都為值
}


}

八、程式控制

8.1 條件控制(重點if)

var b : Int = 5
var a = if(b>5) "a" else 2.0
=> 2.0

val x = 9
val y = if(x==10) x+1 
println(y   )
=> ()
如果說if後面沒有else,則預設else部分的值是Unit,返回()

8.2 塊表示式{}

也是一個結果,{}中最後一行的結構就是快表示式的結果

var a = {
	 var a =6;var b = 5;
      a*b
    }
    println(a)
    =>  30

#賦值語句的結果為Unit
var x = 10
var y = {
	x = x * 2
	//x*2
}
println()
=> ()
// 建立程式碼塊時即建立了一個作用域,在程式碼塊內可以訪問程式碼塊外的實體 (變數、函式、類),反之不成立。因為最後一個是表示式,不是值,輸出為Unit,但是當我加上了x*2後,一切都是值,這個時候就可以列印值40

九、for迴圈

9.1 單迴圈

迴圈

// 迴圈
// 像陣列但不是陣列,如果要轉為陣列,直接在後面.toArray
    var arr = Range.apply(1,10,2)   // 2代表的是步幅為2
    for (elem <- arr) {
      println(elem)
    }

// 更為簡潔的一種方式
    for (elem <- 1 until 10 by 2) {
      println(elem)
    }
=>輸出結果為 1 3 5 7 9
for (i <- 表示式) { 
	statements 
}
  1. 首先,變數 i 不需要宣告。嚴格來說是 i 前面不允許有 val 或 var。i 可以是作 用域內的現有變數。
  2. 其次“<-”是關鍵字,非操作符,類似 Java 中的“:”。
  3. 最後表示式可以是陣列、元組、集合。在 Scala 中 Range 是常用的集合型別, 表示範圍區間。

Range min to/until max by step :指的是從最小值到最大值,步長為多少
to與until的區別:to是到多少,可以取到最大值,until是直到多少,取不到最大值

案例:

    for (i <- 0 to 10 by 2 if i % 3 == 0) {
      println(i)
    }
    // 首先從0  2 4 6 8 10中選擇,可以理解為這是第一個函式的值,然後作為下一個函式的輸入,篩選符合取模3等於0的數,最後篩選出 0 6 
    => 0  6

for (i <- 0 to 10 by 2 if i % 3 == 0 if i > 5) {
      println(i)
    }
=> 6
// 首先根據上面的程式碼可以知道,篩選出0,6 再作為最後一個函式的入口引數,最後可以得到6

9.2 多重迴圈

for (i <- 表示式1;j <- 表示式2;....){
	statements
}


案例:
    for (i <- 1 to 20 if i % 2 == 0; j <- 1 to i if j % 3 == 0) {
      println(s"$i\t$j")
    }
=>4	3   部分結果
  6	3
  6	6
  8	3

 for (elem <- 1 to 100;if elem%7==0;if elem%3==0) {  // ;兩個條件都要滿足
          println(elem)
        }
=> 21  42   63   84

// 小九九



#注意:如果()中有多個表示式,可以使用{}代替,換行寫多條語句
    for {i <- 1 to 20 if i % 2 == 0
         j<-1 to 20 if j%3==0}{
      println(s"$i\t$j")
    }

十、迴圈跳轉語句

scala中沒有break和continue,需要手動導包

    //scala中沒有break,continue  需要手動導包
      import scala.util.control.Breaks._   // ._相當於.*
        breakable {
          for (elem <- 1 to 100) {
              println(elem)
            if (elem%17==0){
              break()
            }
          }
        }

#推導式

十一、資料結構

在 Scala 中,物件一般都有兩種方式建立,一種使用類建立,一種使用其對 應的伴生物件建立,區別在於是否使用 new 關鍵字。本章暫不涉及 OOP 的內容, 瞭解伴生物件建立的方式即可。
Scala資料結構是非常重要的知識點,並且Scala中的資料結構遠比Java豐富、 複雜。但是基本原理都是相同的,比如說陣列、棧、佇列、連結串列、樹、雜湊表。 這裡主要關注線性結構,包括 Array、Seq、List、Map 及 Set 等。
對 比 Java , Scala 中 的 數 據 結 構 都 強 調 了 是 可 變 還 是 不 可 變 , 即 mutable/immutable,預設情況下,Scala 會為使用者選擇不可變的資料結構。兩者 的差別在於:
不可變:初始化後內容不再發生變化。
可變:初始化後內容可以發生變化。

十二 、陣列



相關文章