Scala筆記(一)

T_virus發表於2019-02-16

以下是近期Scala學習過程中的簡單記錄,由於理解能力的問題,初期的東西可能會有不少疏漏和理解錯誤的地方,後期再逐漸改善。如果有不入高手法眼的地方也相當歡迎前來指正。另筆記順序沒什麼依據,完全根據看書的進度來(書名是《Scala程式設計》)

概念理解:
首先Scala鼓勵使用函式式的程式設計風格,這種風格我現在理解為函式應該處理和自己相關的東西,而不關心之外的事件。即處理資料的函式只應該處理資料後返回結果,而某些返回結果的則應該專注於結果的展示。還有儘量少的使用var

一、基本型別和操作符
1.基本型別
與Java相同,有Byte、Short、Int、Long、Char、String、Float、Double、Boolean,除String外,其餘都為Scala成員。使用時Scala社群推薦的風格是使用大寫開頭。
另外Scala中定義了一批基本型別的富包裝類,類似於Java中的包裝類,提供了一些常用的方法。但通過隱式轉換在使用上要方便不少,所有的scala基本型別都有對應的富包裝類,如RichByte、RichShort、RichInt、RichLong、RichChar、RichFloat、RichDouble、RichBoolean。
2.操作符
Scala中操作符分為前置操作符(+、-、!、~,這些操作符也是函式,被定義為unary_開頭的方法,例如unary_+)、中置操作符(所有隻有一個引數的函式都可以作為中置操作符,比如 “abc” indexOf “a”,相當於呼叫”abc”.indexOf(“a”))、後置操作符(不帶任何引數的函式,比如 123 toString)
二、變數
scala中變數定義以var或val開頭,var用於宣告可變變數,val宣告不可變變數,類似於Java中的final。var變數可多次進行重新賦值,val只能賦值一次
變數賦值,例如val a = 0;可以沒加型別宣告,scala會自動推斷型別,也可以手動的加型別宣告 val a:String = "abc"

三、函式
1.函式的定義
大部分和Java中的規範相同,不同之處是Scala中可以使用像+、-這樣的函式名,例如1+2
實際呼叫的是1.+(2)
2.有返回值的函式
以def開頭後加函式名,例如 def fun(a:Int,b:String)={},有兩個引數,一個引數為a型別為Int,另一個為b型別為String,後跟一個等號,在等號前可以宣告函式的返回型別,通常情況下不需要做宣告scala會根據函式體(花括號中的內容)的最後一行表示式的內容(即返回值)來推斷返回型別。Scala也會將函式體最後一行的表示式結果作為函式返回值,而不需要手動的使用return返回。
3.沒有返回值的函式
如果函式沒有返回值,則可以省略函式定義中的等號,返回值型別為Unit(相當於Java中的void,但有些不同,具體的區別後面再講)。 例如 def fun() {println("a")}

有一種情況函式的返回型別的宣告則是必要的,即遞迴函式。
當函式體中只包含一個表示式時,則表示式外的花括號可以省略, 例如:def test(a:Int,b:Int) = a + b。還有Scala中語句結尾的分號是可省略的
3.好吧,還有一個是分號推斷,這個我實在不知道該放到哪個分類下,就寫這兒吧!大意就是大多數正常換行寫程式碼的情況下是不需要寫分號的(當然寫了也可以)。只有在以下一種情況成立的條件下需要分號:
(1)疑問行由一個不能合法作為語句結尾的字結束,如句點或中綴操作符(加、減、乘、除等)
(2)下一行開始於不能作為語句開始的詞
(3)行結束於括號()或方框[]內部

四、類和物件
1.類的定義
使用class關鍵字,例如class test{}
2.類構造器
scala中類的構造器分兩種,一種是主構造器,一種是輔助構造器
主構造器定義於類的定義中。像class test(val name:String,val age:Int)這樣,如同Java一樣當不定義主構造器時,會自動生成一個無參的主構造器。主構造器函式的範圍則在類名後的花括號中,例class test{//這裡即為主構造器}。也有別的規則如下:
主構造器中的引數 生成的欄位、方法
val/var name:String 私有name欄位,生成公共的只讀或者可寫的方法
private val/var name:String 私有name欄位,生成私有的只讀或者可寫的方法
@BeanProperty val/var name:String 同上,有些註解會生成額外Java版的公有的 geter和seter方法
name:String 如果有方法中使用此引數,則生成欄位,等同於 private[this] val name,否則無此欄位
輔助構造器
輔助構造器的名稱為this,輔助構造器中必須呼叫其它的輔助構造器或者是主構造器。
3.單例物件
scala中不能定義靜態成員,而使用單例物件,單例物件的定義使用object關鍵字,且沒有引數,其餘的和類一致。當單例對應與某個類名稱相同時,稱這個單例物件是某個類的伴生物件,且類的伴生物件必須與類定義在同一個檔案中。類和它的伴生物件可以相互訪問之間的私有成員。且單例物件第一次被訪問時才會被初始化
與類不同名的單例物件叫獨立物件,可當作工具類或程式的入口使用
五、控制結構
1.if表示式
語法和Java相同,不同的地方是scala的if語句是有返回值的,例如val res = if(1=2) 1 else 2
2.while迴圈
這個和java沒什麼不同的,且並不會有返回值。由於沒有返回值while迴圈的作用通常是更改某個var的值或者執行I/O操作。所以在可能的情況下並不太建議使用while迴圈
3.for迴圈
for迴圈在scala中有著比較強大的功能。下面逐一介紹
(1)列舉集合類
for(a <- List(1,2,3))此例中<-操作符相當於Java中增強for迴圈中的:操作符。但不需要宣告a的型別,scala會推斷型別
(2)過濾
scala的for迴圈中可以過濾迴圈的集合,通過條件守衛只迴圈其中的某一部分,示例如下:
for(a <- 0 to 10 if(a % 2 == 0)),也可以新增多個條件守衛,守衛之間用分號隔開,不過當使用花括號時可以省略分號

  /*使用小括號時需要加分號*/
  for(a <- 0 to 10 if(a != 1);if(a != 2))
  /*使用花括號時多個條件守衛可以省略分號*/
  for{a <- 0 to 10 
     if(a != 1)
     if(a != 2)
    }

(3)巢狀列舉
迴圈條件中可以加入多個迴圈,每個迴圈都可以帶自己的條件守衛。比如

  for(a <- 0 to 10 if(a % 2 == 0) 
    b <- 0 to 10 if(b % 2) != 0)

(4)流間變數繫結

 /** trimmed被定義在第二個迴圈中,且在第二個條件漂守衛和迴圈體中使用,屬於程式碼簡化方式*/
 for{
    file <- filesHere
    if file.getName.endsWith(".scala")
    line <- fileLines(file)
    trimmed = line.trim
    if trimmed.matches(pattern)
 } println(file + ": " + trimmed)

(5)創造新集合
scala中的for迴圈可以使每次迴圈結果以集合的方式返回,使用的關鍵字為yield,示例如下:

Array arr = Array(1,2,3,4,5,6,7,8,9)
/** 此迴圈產生的結果是一個只包含偶數的陣列,返回的集合型別與迴圈時遍歷的集合型別一致,
需要注意的地方是yield關鍵字應當放到迴圈體之外,也就是如果迴圈體有花括號時yield關鍵字
應當放在迴圈體的花括號之前,for(//迴圈條件) yield {//迴圈體}*/
for(a <- arr if(a % 2 == 0)) yield a

4.異常處理
(1)丟擲異常
語法和Java的相同,throw new RuntimeException()但在scala中丟擲異常的語句是有返回值的,返回值型別為Noting,是所有型別的子類。具體的以後講,現在只先大概瞭解一下。
(2)捕獲異常
使用scala中的一種叫模式匹配的方式進行異常捕獲。語法如下,好像也沒啥可說的。finally子句也和Java中的相同。不同之處是try catch語句也有返回值的。還有最好別在finally子句中使用return返回結果,否則這個返回結果會覆蓋之前的正常try中的結果。

try{
     val f = new FileReader("test.txt")
 }catch{
     case ex:FileNotFoundException => //處理檔案丟失
     case ex:IOException => //處理IO問題
 }finally{

 }

5.變數範圍,這個裡唯一不太一樣的地方是,scala中允許巢狀範圍裡定義同名變數,例如:

   var a =1
   {
    var a = 2
    {
        //此處列印2
        println(a)
    }
   }

相關文章