1. 程式人生 > >02-Scala複雜型別入門

02-Scala複雜型別入門

Scala Programming程式設計指南

汪文君

目錄

目錄 1

寫在最開始的話

其實在很久之前,我有自己學習過一些基於JVM的語言,包括Scala,Groovy,Bshell(不是linux中的shell,是最早的Sun公司出的bshell),但是在工作和日常生活中用不到之後,學習了又會忘記,不知道是不是記憶力不好的原因,但是此次公司決定使用Spark,準確的說是明年第二季度開始使用,所以我又開始整理關於Scala的知識,希望藉著這個機會能夠將Scala的語言特點整理,並且熟練掌握,應用於工作和日常開發之中。

關於Scala這門語言,其實語法量比Java多很多,很多老外建議我使用Clojure,不要使用Scala,他們給出最大的一個槽點就是語法太多,用他們的話講就是完成一件事,scala有太多的方式可供選擇,這樣反倒不太好,但是不管怎樣,既然要去使用這麼語言來餬口養家,那麼就自動遮蔽一些否定的聲音,也許他們說的有道理。

另外一個很重要的話題是,如果你掌握了Java 8,其中一些函數語言程式設計對知識,對學習Scala的幫助非常大,本人利用業餘的時間錄製了一套關於Java 8的視訊教程,大概有40集,全部是針對Java 8新語法和新程式設計思想的實戰,感興趣的可以去下載觀看

2、Scala複雜型別入門

2.1 Scala中的陣列

在上一個電子書中,大致學習了一下如何定義變數,定義函式,以及使用scala指令碼,簡單介紹了一下while迴圈和foreach迴圈,我們在這一節課中我們來使用一些稍微複雜一點的Scala資料型別,就先從Array入手吧

2.1.1 Scala陣列介紹

關於Scala中的資料其實和很多語言中的資料定義完全一樣,說白了就是一個固定空間裡存放著一些型別一樣的資料,比如我們定義一個數組型別為String

val greetingString: Array[String] = new Array[String](3)

當然其中的資料型別也是可以省略的

val greetingString = new Array[String](3)

我們來看看如何給陣列中的元素賦值以及獲取元素的值

    greetingString(0)="Hello"

    greetingString(1)="World"

    greetingString(2)="Scala"

    println (greetingString(0))

    println (greetingString(1))

    println (greetingString(2))

通過for迴圈的方式對其進行輸出

   for (i <- 0 to(greetingString.length - 1))

      println(greetingString(i))

2.1.2 萬物皆物件

上面的例子中,看到紅色加粗的字型了麼,寫法有些奇怪,其實to是數字0的一個方法,數字也有方法?沒錯,在Scala中其實沒有什麼數字操作符可言,更沒有Java中的所謂基本資料型別可言,所有的物件都是物件,0就是一個物件,+-/×這些都不是運算子,而是數字物件的方法,如果單純這一點上來說,scala面向物件的更為徹底,那麼我們再來看看既然是物件,為什麼0後面沒有物件導航符號“.”這是Scala的語言特性,在Scala中如果一個方法只有一個引數,所在物件對其的呼叫可以省略. 甚至引數的括號,我們來看看這個例子

  object ArrayInAction {

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

    ArrayInAction.echo("Hello Scala")

    ArrayInAction echo "Hello Scala"

  }

  def echo(msg: String): Unit = {

    println(msg)

  }

}

2.1.3 再談Array元素的存取

2.2.1中我們看到,獲取的方式是通過(),這一點和Java還是有區別的,這在Scala中其實也是一種簡寫的方法,是由Array的伴生物件提供的,我們來看看,完整的元素存取到底是怎麼樣的

    val greetingString: Array[String] = new Array[String](3)

    greetingString.update(0, "Hello")

    greetingString.update(1, "World")

    greetingString.update(2, "Scala")

    for (i <- 0 to (greetingString.length - 1))

      println(greetingString.apply(i))

同步視訊:

2.2 Scala中的List

Array相比,List是可變長的,這是Java中的關於List的印象,可是在Scala中,List不僅不可變,裡面的元素都不能變

2.2.1 List基本用法

val list1: List[Int] = List(1, 2, 3)

我們定義了一個List,但是這個List不像我們想象的那樣可變長,裡面的元素是可以變化的,對其每一次的操作都會產生一個新的List

val list2: List[Int] = list1.updated(1, 100)

改變了其中的一個元素,就會產生一個新的list

List之間的疊加:::,類似於addAll,但是仍然會產生一個新的List

  val list3: List[Int] = List(1, 2, 3)

  val list4: List[Int] = List(4, 5, 6)

  val joinedList: List[Int] = list3 ::: list4

List append,有點類似我們給Java中的List add元素,但是他是右操作,看看下面的例子

val list5: List[Int] = 8 :: list3

根據我們前面的知識,是不是認為::是數字物件的方法呢?其實不然,這是List中的一個有操作符號,和下面的等價

val list6: List[Int] = list3.::(8)

List中還有一個非常重要物件Nil,他不等同於Lua語言中的nil,不代表NULL的意思,而代表一個空的List.

同步教學視訊:

2.2.2 List的更多用法

List提供的方法比較豐富,相對比Java中的list,方法比較多,我們在這裡大概說一下其中的一些用法

上面的方法,我們不會一一介紹,簡單的說幾個就可以了

l Count

 val count: Int = list.count(i => i > 4)

統計符合條件的元素個數

l Drop

去掉List中前兩位的元素

 val list2 = list.drop(2)

l dropRight

去掉最後面的兩個元素

 val list2 = list.dropRight(2)

l Exists

List中是否存在一個特定的元素

 val exists: Boolean = list.exists(i => i == 8)

l Filter

獲取符合條件的子集

val list2: List[Int] = list.filter(i => i % 2 == 0)

l Forall

判斷List中的所有元素是否滿足條件

val forall: Boolean = list.forall(i => i > 2)

l Map

List中所有的元素都進行某種操作,產生一個新的,比如想讓所有的元素都增大10倍

val map: List[Int] = l4.map(i => i * 10)

2.2.3 同Java 8 的對比

關於List中的很多用法,其實用Java 8 Stream也可以實現類似的函式式效果,我們來看看如何使用Java 8 的stream結合lambda簡潔有效的解決

package com.wangwenjun.chapter2;

import java.util.Arrays;

import java.util.List;

import java.util.Optional;

import static java.util.stream.Collectors.toList;

/***************************************

 * @author:Alex Wang

 * @Date:2016/11/23 QQ:532500648

 * QQ交流群:286081824

 ***************************************/

public class ScalaListFunctionByJava {

    public static void main(String[] args) {

        List<Integer> list = Arrays.asList(1, 2, 3, 5, 6, 7);

        long count = list.stream().filter(i -> i > 4).unordered().count();

        Optional.of(count).ifPresent(System.out::println);

        Optional.ofNullable(list.stream().map(i -> i * 10).collect(toList()))

                .ifPresent(System.out::println);

    }

}

本節同步視訊地址:

2.3 Scala中的Tuple

Tuple也是類似於List的容器,元組也是不可變的,但是它不同於List是因為它可以同時存放多型別的元素

package com.wangwenjun.chapter2

/** *************************************

  *

  * @author:Alex Wang

  * @Date:2016 /11/26

  *            QQ:532500648

  *            QQ交流群:286081824

  ***************************************/

object TupleInAction extends App {

  val t1 = (123, 'X', "Hello");

  println(t1._1)

  println(t1._2)

  println(t1._3)

}

我們簡單定義了一個Tuple,分別存放了數字,字元,字串型別,並且我們通過t1._1等方式對其進行了訪問,在Tuple中沒有apply方法,只能通過下標的方式來獲取,那是因為,apply方法始終返回同類型的資料,但是很明顯Tuple中的元素不具備這樣的條件,更重要的一點是tuple中的元素下標開始是基於1而不是0.

2.4 Scala中的Set和Map

Scala中也存在類似Java的Set和Map,但是他卻有兩種不同的實現,可變與不可變,基於入門的考慮,我們會在後面詳細介紹Set和Map的用法,在這裡只是暫時說說其基本用法

2.4.1 Scala中的Set

package com.wangwenjun.chapter2

/** *************************************

  *

  * @author:Alex Wang

  * @Date:2016 /11/26

  *            QQ:532500648

  *            QQ交流群:286081824

  ***************************************/

object SetInAction extends App {

  var set: Set[String] = Set("Hello", "World")

  println(set)

  println(set hashCode)

  set.+=("Scala")

  set += "Scala"

  println(set)

  println(set hashCode)

  println("=========================")

  set.foreach(println)

}

Set中的元素是不可重複的,我們用預設的方式建立Set,產生的是一個不可變的Set,上面的這段程式碼只是簡單的介紹了一下如何建立Set,如何給Set新增一個元素,關於更加深入的Set知識,我們在後面會詳細說明

2.4.2 Scala中的Map

關於Map也是Key,Value的形式,在Scala中同樣也有Map,只不過更加的豐富,同樣,我們也會在後面專門的章節中詳細介紹

package com.wangwenjun.chapter2

import scala.collection.mutable.Map

/** *************************************

  *

  * @author:Alex Wang

  * @Date:2016 /11/26

  *            QQ:532500648

  *            QQ交流群:286081824

  ***************************************/

object MapInAction extends App {

  import scala.collection.mutable.Map

  val map: Map[Int, String] = Map[Int, String]();

  map.+=(1 -> "Alex")

  map.+=(2 -> "WenJun")

  map.+=(3 -> "Scala")

  map.+=(4 -> "Java")

  val map2: Map[Int, String] = Map(

    1 -> "Alex", 2 -> "Scala", 3 -> "Java", 4 -> "Collection"

  )

  map2.foreach(item => println(item._1 + "," + item._2+" "+item.getClass))

}

2.5 函式式風格初識

我們還是拿迴圈輸出作為函式式的演變,看看下面的程式碼

package com.wangwenjun.chapter2

/****************************************

  *

  * @author:Alex Wang

  * @Date:2016 /11/26

  *            QQ:532500648

  *            QQ交流群:286081824

  ***************************************/

object FunctionInAction {

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

    val array: Array[String] = Array("Hello", "World", "Scala", "Java")

    printArray(array)

    printArrayForEach(array)

    printArrayFunction(array)

    val map: Map[Int, String] = Map[Int, String](

      1 -> "Hello", 2 -> "World", 3 -> "Scala", 4 -> "Java"

    )

    map.foreach(printMap)

  }

  def printMap(item: Tuple2[Int,String]) = println(item._1 + " <=> " + item._2)

  def printArray(array: Array[String]): Unit = {

    for (v <- array)

      println(v)

  }

  def printArrayForEach(array: Array[String]): Unit = {

    array.foreach(println)

  }

  def printArrayFunction(array: Array[String]) = array.foreach(println);

}

上面的例子我們從printArray一直到printArrayFunction越來越函式化的演變,並且對Map的foreach進行了函式式的改進。

2.6 Scala和檔案

在本小節中,我們簡單的介紹一下Source型別,知道如何通過source獲取檔案的內容,關於更多檔案操作的內容我們會在後面的章節中專門介紹

package com.wangwenjun.chapter2

package com.wangwenjun.chapter2

import java.io.File

import scala.io.Source

/** *************************************

  *

  * @author:Alex Wang

  * @Date:2016 /11/26

  *            QQ:532500648

  *            QQ交流群:286081824

  ***************************************/

object SourceInAction extends App {

  val file: File = new File("C:\\Users\\wangwenjun\\IdeaProjects\\scalaInAction\\src\\com\\wangwenjun\\chapter2\\SourceInAction.scala");

  val source: Source = Source.fromFile(file)

  val content: Iterator[String] = source.getLines

  for (line <- content)

    println(line)

  source.close()

}

寫在最後的話

本節課的內容大概就這麼多,我們會逐步的更新,為了能夠讓讀者儘快看到最新的內容,沒更新一次就會發布一次,不用等到搞定一切之後再做統一發布,有問題可以和我交流,我們一起共同學習,共同進步,期待著你們的建議。