scala學習筆記


java程序員的scala基礎學習筆記,只記錄了些基礎知識。

hello world

package blog

object HelloWorld {
   /* 這是我的第一個 Scala 程序
    * 以下程序將輸出'Hello World!' 
    */
   def main(args: Array[String]) {
      println("Hello, world!") // 輸出 Hello World
   }
}

關鍵字轉義

與關鍵字同名,需要轉義,例

Thread.`yield`();

yield爲關鍵字,需要加引號轉義

數據類型

在這裏插入圖片描述

變量

scala可以算是弱類型的,用法與js中的有些相似。

var定義變量,val定義常量

      var a = 1;  //變量
      val b = 2;  //常量

scala同樣支持強類型的定義方法

var a : Int = 1;

具體語法爲

var VariableName : DataType [=  Initial Value]

或

val VariableName : DataType [=  Initial Value]

元組

在 Scala 中,元組是一個可以容納不同類型元素的類。 元組是不可變的。
當我們需要從函數返回多個值時,元組會派上用場。

var py: (Int, String) = (40, "")

很python的感覺,就用py來命名了。

這東西感覺就像是另一種Object[]一樣,只是多了一些特有的方法與限制

另一種更顯式的寫法

var py2: Tuple2[Int, String] = (40, "")

Tuple2 是類型,後面的數字是數組的元素數量,Tuple2 大致相當於 Object[2]

訪問元素

可以用下標取值

    var py2: Tuple2[Int, String] = (40, "str")
    
    println(py2._1)
    println(py2._2)
解構
    var py2: Tuple2[Int, String] = (40, "str");
    
    var (v1, v2) = py2;
    
    println(v1);
    println(v2);
模式匹配(case when)
    val planetDistanceFromSun = List(("Mercury", 57.9), ("Venus", 108.2), ("Earth", 149.6), ("Mars", 227.9), ("Jupiter", 778.3))

    planetDistanceFromSun.foreach { tuple =>
      {
        tuple match {
          case ("Mercury", distance) => println(s"Mercury is $distance millions km far from Sun")
          case p if (p._1 == "Venus") => println(s"Venus is ${p._2} millions km far from Sun")
          case p if (p._1 == "Earth") => println(s"Blue planet is ${p._2} millions km far from Sun")
          case _ => println("Too far....")
        }
      }
    }
for中的使用
val numPairs = List((2, 5), (3, -7), (20, 56))

for ((a, b) <- numPairs) {
  println(a * b)
}

函數變量

val addOne = (x: Int) => x + 1
println(addOne(1)) // 2

方法

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

與函數不同,方法中可以做更多事情

      def add(x: Int, y: Int): Int = {
        var nv = 9; 
        return x + y + nv
      }
      println(add(1, 2)) // 12

甚至多個參數列表

      def addThenMultiply(x: Int, y: Int)(multiplier: Int): Int = (x + y) * multiplier
      println(addThenMultiply(1, 2)(3)) // 9

訪問修飾符

private,protected,public。缺省爲public
與java不同的地方

private

private,更嚴格,只在內部可見。也即外部類中不可見,雖然也沒人那麼用就是了。用java代碼來表示就是類似下面這樣的代碼將變得非法

public class Test02 {

	public static void main(String[] args) {
		int w = new Test02().new Inner().i;
	}
	
	class Inner{
		private int i = 1;
	}
	
}

用scala代碼來表示

class Outer{
    class Inner{
    private def f(){println("f")}
    class InnerMost{
        f() // 正確
        }
    }
    (new Inner).f() //錯誤
}

protected

比java更嚴格,只有當前類,子類可訪問

循環

for

查了不少資料,確實有很多種寫法,但是本質上都只是foreach,這東西沒什麼靈活性,隨便記幾個例子好了。

    for (i <- 1 to 3) {
      println(i)
    }

普通for循環

case class User(name: String, age: Int)

val userBase = List(User("Travis", 28),
  User("Kelly", 33),
  User("Jennifer", 44),
  User("Dennis", 23))

val twentySomethings = for (user <- userBase if (user.age >=20 && user.age < 30))
  yield user.name  // i.e. add this to a list

twentySomethings.foreach(name => println(name))  // prints Travis Dennis

循環裏面加了個判斷,並且用了yield關鍵字——scala的for循環可以通過yield使用返回值

while

與java中的一致

        var i : Int= 0;
        while(i < 3){
          println(i)
          i+=1;
        }

循環控制

scala中不直接提供break、continue語法,需要額外加一些東西

import util.control.Breaks._

object Test01 {
  def main(args: Array[String]): Unit = {
    //foreach break
    breakable{
      for (i <- 1 to 10) {
        println(i)
        if (i == 3)
          break;
      }}
    //foreach continue
    for (i <- 1 to 10) {
      breakable {
        if (i == 3)
          break
        println(i)
      }
    }
    //while break
    breakable{
      var i : Int = 0;
      while (i < 10) {
        println(i);
        if(i == 1)
          break;
      }}
    //while continue
    var i : Int = 0;
    while (i < 10){
      breakable{
        println(i);
        if(i == 1)
          break;
      }
    }
    
  }
}
嵌套循環控制

大致相當於java中的這種語法

		//java
		a: for(int i = 0; i < 3; i++){
			break a;
		}
import util.control.Breaks._
import scala.util.control._

object Test01 {
   def main(args: Array[String]) {
      var a = 0;
      var b = 0;
      val numList1 = List(1,2,3,4,5);
      val numList2 = List(11,12,13);

      val outer = new Breaks;
      val inner = new Breaks;

      outer.breakable {
         for( a <- numList1){
            println( "Value of a: " + a );
            inner.breakable {
               for( b <- numList2){
                  println( "Value of b: " + b );
                  if( b == 12 ){
                     inner.break;	//內層break
                     //outer.break;	//直接跳出外層
                  }
               }
            } // 內嵌循環中斷
         }
      } // 外部循環中斷
   }
}

方法與函數

  • Scala 有方法與函數,二者在語義上的區別很小。Scala 方法是類的一部分,而函數是一個對象可以賦值給一個變量。換句話來說在類中定義的函數即是方法。
  • Scala 中的方法跟 Java 的類似,方法是組成類的一部分。
  • Scala 中的函數則是一個完整的對象,Scala 中的函數其實就是繼承了 Trait 的類的對象。
  • Scala 中使用 val 語句可以定義函數,def 語句定義方法。

這段來自菜鳥教程的話可以帶來一個直觀的認識——方法與函數基本可以看做一種東西的兩種寫法。

A Function Type is (roughly) a type of the form (T1, …, Tn) => U, which is a shorthand for the trait FunctionN in the standard library. Anonymous Functions and Method Values have function types, and function types can be used as part of value, variable and function declarations and definitions. In fact, it can be part of a method type.

A Method Type is a non-value type. That means there is no value - no object, no instance - with a method type. As mentioned above, a Method Value actually has a Function Type. A method type is a def declaration - everything about a def except its body.

雖然有許多不同,不過把方法當做java的方法來用,函數當做js的函數來用大概就可以了的感覺。

方法

定義:

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

需要注意一下的是方法裏面甚至可以再寫一個方法(允許嵌套方法)

方法可以接受多個參數列表

def addThenMultiply(x: Int, y: Int)(multiplier: Int): Int = (x + y) * multiplier
println(addThenMultiply(1, 2)(3)) // 9
方法的返回值

: [return type] 定義返回值類型,Unit相當於java中的void,不過即使定義了Unit,也依然可以使用return語句或者使用輸出語句將方法打印,不過輸出結果都是(),一個空的元組。

object Test02 {
  def main(args: Array[String]): Unit = {
    println(mhd() == ());  //true
  }
  
  def mhd() : Unit = {
    return 123;
  }
}

方法中允許省略return關鍵字,並將最後一行的結果自動識別爲返回值。
不過怎麼想都是個雞肋的特性,先不說不少方法都需要多個return來控制邏輯,return這個關鍵字本身也會有一個提示的作用,幫助更快的理解代碼。

函數

函數的一般寫法

    ((x: Int) => x + 1);              //定義匿名函數
    ((x: Int) => println(x))(1);      //調用匿名函數  
    println(((x: Int) => x + 1)(1));  //調用匿名函數並輸出返回值
    
    var aa = (x: Int, y: Int) => x + y + 1;  //定義多個參數
    
    (x: Int, y: Int) => {
      var z = x + y;
      z + 1;
    };   // 使用塊來調用多行代碼
高階函數

higher-order function,就是把函數當變量用,可以作爲參數,也可以作爲返回值。

  • 函數作爲參數
    var fc = (f : Int => String) => f(1);
    println(fc((x) => "" + x));

解釋:上面代碼中的Int爲型參f函數在fc函數中的參數類型,String爲f的返回類型。

如果f有多個參數,可以這樣寫

    var fc = (f : (Int, Int) => String) => f(1, 2);
    println(fc((x, y) => "" + x + y));
  • 將函數作爲返回值的函數
    var ff = () => {(a : Int, b : Int) => {a + b}};
    
    var backFunc = ff();
    println(backFunc(1, 2));

提示:(a : Int, b : Int) => {a + b} 是函數ff所返回的匿名函數

與java的整合

scala作爲在jvm上執行的語言,基本可以直接調用java代碼,但是在一些細節上還是有一些差距,需要記錄一下。

網上沒找到相關資料,想到一個記一個。


scala會默認引用引用java.lang.*中的,這一點與java一致。若引用別的包,需要手動import。scala對import進行了一定程度的擴展,但是也是完全兼容java語法的。

scala中使用java.util.ArrayList

scala肯定是由自己的集合實現的(https://www.scala-lang.org/api/current/scala/collection/immutable/List.html),但是也可以直接使用java中的類。

import java.util.ArrayList

object Test02 {
  
  def main(args: Array[String]): Unit = {
    
    var list = new ArrayList
    println(list.size());
    
  }
}

這裏list應該是不能直接添加值的

    var list = new ArrayList;
    list.add("");

這麼寫會報錯,需要指定泛型

    var list = new ArrayList[String];
    list.add("");

java與scala對象互相轉換

集合

    import scala.collection.JavaConverters._

    val list: java.util.List[Int] = List(1, 2, 3, 4).asJava
    list.size();    //java object
    
    val buffer: scala.collection.mutable.Buffer[Int] = list.asScala
    buffer.length;  //scala object

簡單來說,需要先引入import scala.collection.JavaConverters._

具體規則在官方文檔中有詳細說明
https://www.scala-lang.org/api/current/scala/collection/JavaConverters$.html
抄過來一點
The following conversions are supported via asScala and asJava:

scala.collection.Iterable       <=> java.lang.Iterable
scala.collection.Iterator       <=> java.util.Iterator
scala.collection.mutable.Buffer <=> java.util.List
scala.collection.mutable.Set    <=> java.util.Set
scala.collection.mutable.Map    <=> java.util.Map
scala.collection.concurrent.Map <=> java.util.concurrent.ConcurrentMap

The following conversions are supported via asScala and through specially-named extension methods to convert to Java collections, as shown:

scala.collection.Iterable    <=> java.util.Collection   (via asJavaCollection)
scala.collection.Iterator    <=> java.util.Enumeration  (via asJavaEnumeration)
scala.collection.mutable.Map <=> java.util.Dictionary   (via asJavaDictionary)

In addition, the following one-way conversions are provided via asJava:

scala.collection.Seq         => java.util.List
scala.collection.mutable.Seq => java.util.List
scala.collection.Set         => java.util.Set
scala.collection.Map         => java.util.Map

The following one way conversion is provided via asScala:

java.util.Properties => scala.collection.mutable.Map

In all cases, converting from a source type to a target type and back again will return the original source object. For example:

import scala.collection.JavaConverters._

val source = new scala.collection.mutable.ListBuffer[Int]
val target: java.util.List[Int] = source.asJava
val other: scala.collection.mutable.Buffer[Int] = target.asScala
assert(source eq other)

Alternatively, the conversion methods have descriptive names and can be invoked explicitly.

scala> val vs = java.util.Arrays.asList("hi", "bye")
vs: java.util.List[String] = [hi, bye]

scala> val ss = asScalaIterator(vs.iterator)
ss: Iterator[String] = <iterator>

scala> .toList
res0: List[String] = List(hi, bye)

scala> val ss = asScalaBuffer(vs)
ss: scala.collection.mutable.Buffer[String] = Buffer(hi, bye)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章