Scala語言學習


Scala的程序被編譯成Java字節碼(生成class文件),所以可以運行在JVM上,並且可以調用Java的類庫,兼容Java程序。

Scala 是一門多范式(multi-paradigm)的編程語言,設計初衷是要集成OOP和函數式編程(FP)的各種特性:

  1. 面向對象特性:Scala是一種純面向對象的語言,每個值都是對象。類名:采用PascalCase命名(如class MyFirstScalaClass)。方法名:采用camleCase命名(如def myMethodName())。與Java類似,變量命名也采用camelCase方式。Scala類擴展有兩種途徑:一種途徑是子類繼承(單繼承),另一種途徑是靈活的混入機制。這兩種途徑能避免多重繼承的種種問題。
  2. 函數式編程:即函數也能當成值來使用。可以定義匿名函數、高階函數、多層嵌套函數,並支持柯里化。Scala的case class、內置的模式匹配相當於FP的代數類型。利用Scala的模式匹配可以處理XML數據(這個過程類似於正則表達式)。
  3. 靜態類型:即Scala具有的類型系統,編譯時先檢查類型,保證了代碼的安全性、一致性。類型系統包含:泛型類、協變和逆變、標注、類型參數的上下限約束、把類別和抽象類型作為對象成員、復合類型、引用自己時顯示指定類型、視圖、多態方法。
  4. 擴展性:
  5. 並發性:使用Actor作為並發模型,但它不同於Thread,它相當於Thread的實體。在Scala中,多個Actor可以分別復用/使用同一個線程,因此可以在程序中可以使用數百萬個Actor,而線程只能創建數千個,在2.10之后的版本中,使用Akka作為其默認Actor實現。Actor通過郵箱收發消息。——線程復用:線程的數量必須加以控制,因為盲目的大量創建線程反而會降低系統性能。於是不狂增數量,而是將已創建的線程進行重復使用,即線程使用完畢,不立即銷毀,而是暫時放在連接池(其狀態肯定是空閑了),以供下次可以繼續使用這些已有的線程,而不必創建新的。

Scala比較流行的Web框架:Lift框架、Play框架。

1、腳本編程:運行一個HelloWorld的程序(保存到HelloWorld.scala文件中,文件名應與類名相同,否則無法編譯):

object HelloWorld {
    def main(args: Array[String]): Unit = {
        println("Hello, world!")
    }
}

在終端中,運行:scala HelloWorld.scala,即可輸出。

2、Scala也可以交互式編程(進入終端):

當要使用的標識符(方法名等)與關鍵字沖突之時,要使用這個標識符就需要寫在一對倒引號`之間,如線程的yield方法:Thread.`yield`()。

定義Scala的包:

1、第一種方法類似於Java,在一個文件開頭定義包名,則該文件后面的所有代碼都屬於這個包:

package com.qunyh;
class HelloWorld() {
}

2、第二種方法類似於C#,指明包的作用域,於是一個文件中可以定義多個包:

package com.qunyh {
    class HelloQunyh {
    }
}

引用包(可以引用Java的包):

import java.awt.Color    //只引入Color類
import java.awt._    //引入包內所有成員

多行字符串:

val foo = """菜鳥教程
www.runoob.com
www.w3cschool.cc
www.runnoob.com
以上三個地址都能訪問""";    //這是一個字符串,只不過是分多行:在一對"""之間

變量的聲明:

一般變量用var聲明,常量用val聲明(這種聲明的常量值以后就不能修改了,不然編譯會報錯)。

//可以指明變量類型(這種聲明的時候可以不用初始化): 注意類型的位置
var myVar : String = "Foo";
val myVal : String = "Foo";
//也可以不指明(此時必須初始化,才能類型推斷)
var yourVar = "Foo";
val yourVal = "Foo";
//多個變量一起聲明
var xmax, ymax = 100;    //兩個變量值都為100

聲明一個元組:

訪問修飾符:

基本和Java一樣,如果沒有指定,默認訪問級別是public。但是Scala的限定比Java更嚴格。

for循環:

1、第一種結構是for( var x <- Range ):其中Range區間可以是i to j或者i until j;而左箭頭<-用於為變量x賦值。

object HelloWorld {
    def main(args: Array[String]): Unit = {
        var x = 0;
        //for(x <- 1 to 10)
        for(x <- 1 until 10) {
            println("hello");
        }
    }
}
object Test {
   def main(args: Array[String]) {
      var a = 0;
      var b = 0;
      // 相當於二重循環:
      //for(int a = 1; a <= 3; a++)
      //    for(int b = 1; b <= 3; b++)
      for( a <- 1 to 3; b <- 1 to 3){
         println( "Value of a: " + a );
         println( "Value of b: " + b );
      }
   }
}

2、第二種結構for( var x <- List ):其中 List 變量是一個集合,for 循環會迭代所有集合的元素:

object Test {
    def main(args: Array[String]) {
        var a = 0;
        var numList = List(1, 2, 3, 4);
        for(a <- numList) {
            println(a + "");
        }
    }
}

與其他的動態語言類似,Scala也有過濾器:

object Test {
    def main(args: Array[String]) {
        var a = 0;
        var numList = List(1,2,3,4,5,6,7,8,9,10);
        for(a <- numList
            if a % 2 == 0; if a < 5) {
                println(a + "");
        }
    }
}

而且還可以把List中過濾后剩下的,作為新的List返回(只是這種for循環的寫法有點不同):

object Test {
    def main(args: Array[String]) {
        var a = 0;
        var numList = List(1,2,3,4,5,6,7,8,9,10);
        var retList = for{ a <- numList
            if a % 2 == 0; if a < 5 } yield a;    //這種for循環就不帶循環體了
        for(a <- retList) {
            println(a + "");
        }
    }
}

Scala的循環控制語句沒有break、continue等,但是提供了另一種語法來實現break語句的效果(需要導入control包)。

import scala.util.control._
object Test {
    def main(args: Array[String]) {
        var a = 0;
        var control = new Breaks;
        var numList = List(1,2,3,4,5,6,7,8,9,10);
        //建議
        control.breakable {
            for(a <- numList) {
                println(a + "");
                if(a == 5) {
                    control.break;
                }
            }
        }
        for(a <- numList) {
            println(a + "");
            if(a == 5) {
                control.break;
            }
        }
    }
}

函數

Scala 有函數和方法,二者在語義上的區別很小。Scala 方法是類的一部分,而函數是一個對象可以賦值給一個變量。我們可以在任何地方定義函數,甚至可以在函數內定義函數(內嵌函數),但是作用域就受到了限制。

Scala 函數聲明格式如下:

def functionName ([參數列表]) : [return type];

如果不寫等於號和方法主體(只有聲明),那么方法會被隱式聲明為"抽象(abstract)",包含它的類型(在類中)於是也是一個抽象類型。

函數定義格式如下(含body),其中返回值可以是任意的Scala數據類型:

def functionName ([參數列表]) : [return type] = {
    function body
    return [expr]
}

閉包:

Scala的閉包與C#的Lambda表達式類似,例如:

val multiplier = (i:Int) => i * factor;    //這就是一個閉包:箭頭的左邊是形參,右邊是body(可能含返回值)。整個閉包可以當作一個函數,賦給一個變量

Scala的字符串:

String類型:

Scala本身沒有String類,其類型實際上是Java String(java.lang.String),而Java的String對象的值是不可變的,如果修改字符串則意味着會產生一個新的字符串對象(暫時還沒搞清楚,但我覺得是這個意思:修改之前=右邊是一個字符串常量對象,變量只是引用其地址,而修改之后就是創建了一個新的字符串常量對象,變量只是更改其引用地址)。與Java、C#類似,要創建一個可修改的字符串,可以使用StringBuilder類。

StringBuilder類:

object Test {
    def main(args: Array[String]) {
        val buf = new StringBuilder;
        buf += 'a';
        buf ++= "bcdef";    //都不會重新創建對象
        println( "buf is : " + buf.toString );
    }
}

數組:

var z = Array("Runoob", "Baidu", "Google");
var z:Array[String] = new Array[String](3);
//多維數組
var myMatrix = ofDim[Int](3,3);
//合並數組
var myList1 = Array(1, 2, 3);
var myList2 = Array(4, 5, 6);
var myList3 =  concat( myList1, myList2);    //123456;concat函數:import Array._;
//創建區間數組:使用range方法,返回一個數組Array
var yourList1 = range(10, 20, 2);    //arg3是步長,默認為1(不包含20)

集合:

Scala提供了一些集合類型的抽象,分為可變集合、不可變集合。

  • 可變集合可以在適當的時候更新或擴展,即添加、移除、修改一個集合元素。
  • 不可變集合一旦創建,其本身永遠不會改變。但是仍然可以"模擬"可變集合的操作,這些操作還是不會改變不可變集合本身,卻可以返回一個新的集合(新集合是否可變)。
// 常見的集合:
// 定義整型 List
val x = List(1,2,3,4)
// 定義 Set
var x = Set(1,3,5,7)
// 定義 Map
val x = Map("one" -> 1, "two" -> 2, "three" -> 3)
// 創建一個元組(這里包含兩個不同類型元素)
val x = (10, "Runoob")
// 定義 Option
val x: Option[Int] = Some(5)

迭代器Iterator:

Iterator不是集合,而是一種訪問集合的方法。迭代器的兩個基本操作是next(返回集合中、迭代器的下一個元素,並更新迭代器自身的狀態)和hasNext(判斷集合中、迭代器的下一個元素是否存在)方法。可以先看代碼,然后更容易理解:

object Test {
    def main(args: Array[String]) {
        val it = Iterator("Baidu", "Google", "Runoob", "Taobao");
        while (it.hasNext){
            println(it.next())
        }
        //還可以利用迭代器,很方便的查找max、min
        var ita = Iterator(20,40,2,50,69, 90);
        println("最小:" + ita.min);
        //println("最小:" + ita.min);
        //println("最大:" + ita.max);    //一個迭代器,max、min只能用一次(再用就不支持操作),就算是用兩次min也不行
        //我的理解是:迭代器是迭代地找max、min,找到即遍歷完整個"集合",就停止迭代了,
        //再次使用就會拋出異常java.lang.UnsupportedOperationException
        
        //獲取迭代器的長度size或length:即可以迭代的次數
        //和min、max的用法相似:所以第一次是6,以后就是0了
        var itb = Iterator(20,40,2,50,69, 90);
        println(itb.size + ":" + itb.length);
        //println(itb.size + ":" + itb.size);
    }
}

Scala類與對象:

創建一個類和類的實例:

//Point類文件
class Point(val xc: Int, val yc: Int) {
  var x: Int = xc;
  var y: Int = yc;
  
  def move(dx: Int, dy: Int) {
    x = x + dx;
    y = y + dy;
    println("x 的坐標為:" + x);
    println("y 的坐標為:" + y);
  }
}
//主函數
object Test {
  def main(args: Array[String]) {
    //創建一個Point對象
    var pt = new Point(10, 20);
    pt.move(10, 10);
  }
}

Scala繼承:

//繼承剛才的Point類:Location類文件
class Location(override val xc: Int, override val yc: Int, val zc: Int) extends Point(xc, yc) {
  var z: Int = zc;
  
  def move(dx: Int, dy: Int, dz: Int) {
    x = x + dx;
    y = y + dy;
    z = z + dz;
    println("x 的坐標為:" + x);
    println("y 的坐標為:" + y);
    println("z 的坐標為:" + z);
  }
}
//主函數
object Test {
  def main(args: Array[String]) {
    //創建一個Point對象
    var lc = new Location(10, 20, 10);
    lc.move(10, 10, 10);
  }
}

Scala Trait(特征):

特征相當於Java的接口,但是Scala的特征功能卻更為強大。與接口不同,特征可以定義屬性,還可以定義方法的實現,而Java接口卻不能有實現(只能是抽象方法,而且接口不能包含成員變量,除了 static 和 final 變量)。因此在這個方面Trait更像Java的抽象類(可以有抽象方法與非抽象方法),但是抽象類只能是單繼承,所以我覺得在Java中,接口就像是抽象類的精簡版(只有定義,沒有實現),而Scala Trait則像是結合了抽象類、接口,就像是一種可以多繼承(接口)的抽象類。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM