學習Scala: 初學者應該了解的知識


[comment]: # 學習Scala: 初學者應該了解的知識

Scala開發參照清單

這里列出在開發一個Scala工程中需要參照的資料。

官網網站

http://www.scala-lang.org/

文檔網站

http://docs.scala-lang.org/index.html

Cheatsheet

http://docs.scala-lang.org/cheatsheets/

代碼風格

http://docs.scala-lang.org/style/

設計模式

https://wiki.scala-lang.org/display/SYGN/Design+Patterns

Language Specification

http://www.scala-lang.org/files/archive/spec/2.11/

API

http://www.scala-lang.org/api/current/#package

Scala wiki

https://wiki.scala-lang.org

Scala Tools and Libraries

https://wiki.scala-lang.org/display/SW/Tools+and+Libraries

Scala的初次約

Scala是由Martin Odersky設計的一種結合了函數式編程(不僅僅有這個)的強類型語言。
Scala的代碼會被編譯成Java bytecode,並在JVM上運行的。
可以認為Scala是Java的擴充,一個Java語言的超集。
Scala的設計思想之一,來自於對Java語言的一些缺點的批評。

個人也覺得Java語言發展的太慢,尤其是和C#、.NET相比。
Scala的橫空出世,提供了一個積極性的靈感,解決了Java語言的發展問題,給Java社區帶來強大的活力。

Scala的優勢

  • Java有的優勢,Scala都有

  • Scala的編程風格更簡潔

Scala的簡潔風格,也很可能降低可讀性。所以在團隊開發中,還是需要一個良好的代碼規范來約束。

  • 性能很好
    和Java的性能一樣,比Python快的太多了。
  • 可以直接使用Java類庫。
  • Java也可以使用Scala的類庫。
    個別情況下,需要在Scala里做特殊的支持。

Scala的用途

  • 結合Spark,處理大數據。
    這是,目前,Scala的一個主要應用。Spark也是那Scala寫的。

  • Java的腳本語言版
    可以直接寫Scala的腳本,也可以在.sh直接使用Scala。

  • 代替Java。
    scala希望提供一種簡潔的語言。不過作為初學者的我,scala極其容易導致代碼的可讀性比較差。
    Java語言還是有其優勢。

Scala的代碼風格

由於Scala結合了函數式編程和面向對象語言特征,從這個方面看,有兩種編程風格可以選用。

  • 支持函數式編程的面向對象編程風格
  • 函數式編程風格

如果你開發的項目主要用於處理數據,函數式編程風格更適用。
本文也主要針對函數式編程風格。

安裝scala

可以從scala的官方網站上下載。
許多人會選擇Intellij IDEA或者Eclipse作為scala的編輯器。

這里有個使用Visual Studio Code作為編輯器的介紹:
Scala on Visual Studio Code

函數式編程到底意味着什么

請參考:函數式編程 : 一個程序猿進化的故事

Scala的再認識

trait, class,object

開始學習Scala會看到trait這個奇怪的詞,而且可以def object。這里解釋一下:
trait: 類似於Interface,不過可以實現聲明的方法。
class: 就是class.
object: 就是Module,一個靜態類。

Scala的語言特征

除了Java的語言特征外,Scala還提供了一下主要特征。
(這個章節比較深奧,可能不足,需要慢慢地更新)

函數式編程(functional programming)

上面已經說過了。

類型推測(typing inference)

這個特征C#也有。建議大家盡量使用這個特點。也就是說

  • 避免定義變量的數據類型
    一個好處是類型發生變化的時候,改動的代碼會相對較少。
  • 對於函數,要定義輸入和輸出的數據類型。

implicit特性

我把對implicit的認識分為這幾個Levels。

Level 0: 完全忽略implicit的存在

如果,你在你的項目里發現有人使用implicit,可以理直氣壯地批評,這是降低可讀性的傑作。
implicit特性應該避免被使用。implicit很可能給讀代碼的人帶來困惑,屬於反直覺的代碼。

Level 1:簡單的認識implicit conversions

比如:一個函數的參數的Long型,調用時輸入一個Int型的數據,也不會出錯,
其后面就是implicit conversions功勞。
implicit conversions邏輯發現類型Int/Long不匹配,
然后在一個implicit view(可以看成一個函數pool,包含了所有的implicit functions)中找一個輸入為Int,輸出為Long的函數,
最后通過這個函數完成類型的轉換。
Scala自身提供了一些必要的implcite conversion functions.

Level 2: 對implicit的有個基本理解

implicit的使用

使用起來很簡單,直接把implicit關鍵字,加到trait/class/object/def/val之前就可以。
在Scala 2.10版后, implicit可以用在三個地方:
例如:

  • implicit functions vs implicit conversions
implicit def int2ordered(x: Int): Ordered[Int] = 
  new Ordered[Int] { /* .. */ }
  • implicit classes
    implicit classes是針對Pimp-my-library pattern,在Scala語法上的實現。
    這個和C#的extesion methods的用意是一樣的。
    比如,你想在Scala的List類上,增加一個函數,而不用去修改Scala的發布包,
    在Scala 2.10版以后,就可以通過implicit classes實現,
    之前的版本,可以通過Pimp-my-library pattern實現。
    在下面這個例子中,如果import Helpers._,類IntWithTimes的所有方法都會作用於Int上。
object Helpers {
  implicit class IntWithTimes(x: Int) {
    def times[A](f: => A): Unit = {
      def loop(current: Int): Unit =
        if(current > 0) {
          f
          loop(current - 1)
        }
      loop(x)
    }
  }
}
  • implicit values vs implicit parameters
    來自官方的一個例子:
object ImplicitTest extends App {
  /** 
   *  To show how implicit parameters work, 
   *  we first define monoids for strings and integers. 
   *  The implicit keyword indicates that the corresponding object can be used 
   *  implicitly, within this scope, as a parameter of a function marked implicit. 
   */
  implicit object StringMonoid extends Monoid[String] {
    def add(x: String, y: String): String = x concat y
    def unit: String = ""
  }
  implicit object IntMonoid extends Monoid[Int] {
    def add(x: Int, y: Int): Int = x + y
    def unit: Int = 0
  }
  /** 
   *  This method takes a List[A] returns an A which represent the combined 
   *  value of applying the monoid operation successively across the whole list. 
   *  Making the parameter m implicit here means we only have to provide 
   *  the xs parameter at the call site, since if we have a List[A] 
   *  we know what type A actually is and therefore what type Monoid[A] is needed. 
   *  We can then implicitly find whichever val or object in the current scope 
   *  also has that type and use that without needing to specify it explicitly.
   */
  def sum[A](xs: List[A])(implicit m: Monoid[A]): A =
    if (xs.isEmpty) m.unit
    else m.add(xs.head, sum(xs.tail))
  /** 
   *  Here we call sum twice, with only one parameter each time. 
   *  Since the second parameter of sum, m, is implicit its value is looked up
   *  in the current scope, based on the type of monoid required in each case, 
   *  meaning both expressions can be fully evaluated.
   */
  println(sum(List(1, 2, 3)))          // uses IntMonoid implicitly
  println(sum(List("a", "b", "c")))    // uses StringMonoid implicitly
}
implicit的功能可以分為兩類:
  • implicit conversions (from implicit functions and implicit classes)
    當Scala發現類型不匹配,或者正在調用一個對象不存在的函數時,
    Scala compiler就會去implicit function list中找一個匹配的函數。

  • implicit arguments (from implicit values and implicit objects)
    在函數上可以定義一個implcit參數,編譯器會在implicit的對象列表中,
    找到一個類型匹配的對象,並傳入。

作用域

可以想到,implicit有個作用域。這個作用域,和當前的package,以及import的類,
還有Scala的默認有關。

Level 3: 重申:避免使用implicit

Level 4: 如果要使用implicit

  • 好好閱讀關於implicit作用域,編譯器的查找complicit對象的順序等知識。
  • 定義implicit的開發規范
  • 寫好文檔幫助開發人員和用戶理解。
  • 限制其使用的場景
    • 你要實現一個類似於虛數這樣的新數據類型。
    • ...

Collection

請看Scala Collection簡介

Mutability vs Immutability

可變的變量(Mutable variables)(主要是可變的對象)會引起一些潛在的問題:

  • 變化后,可能在map中找不到了
  • 性能損失(在多線程下,讀寫需要加鎖)

編程方面的建議是:

  • 如果可能,使用和開發 immutable 類。

雜七雜八

_ 的用途

請請看Scala underscore的用途

Null, null, Nil, Nothing, None, and Unit

  • Null是Scala中的一個Trait.

  • null是一個Null的實例,相當於Java中的null。在面向函數編程中,不要使用,用None代替。

  • None是一個None.type的實例,代替null。
    在一個函數中,用於表達這個函數返回了沒有值。可以避免 null pointer exception。

  • Unit是Scala中的一個類型,用於表示一個函數沒有返回值。
    有點像Java中的void,不過其實返回了'()'。

  // There is no '=' before '{', so the function return Unit.
  def funUnit(x: Int) {
    x * x
  }

  // There is a '=' before '{', 
  // so the function returns the value of the last expression.
  def funReturnLastStatement(x: Int) = {
    x * x
    x + x
  }

  // Recommend to use explicit return type, and = forever.
  def funReturnLastStatementGood(x: Int) : Int = {
    x * x
    x + x
  }
  • Nil 是一個空的List實例.
  • Nothing是Scala中的一個Trait。基本上沒有用。(我猜的)

## 和 == 對 equals 和 hashCode

在Scala中, ##方法相當於Java中的hashCode方法。
方法相當於Java中的equals方法。
建議使用##和
,因為Scala針對value類型實現額外的功能。

Generic classes/functions: +T, -T, <:, >:, <&

  • +T: 作用於class, 用於協變(covariant)
  • -T:作用於class, 用於逆變(contravariant)

+T, -T 作用於泛型對象之間賦值。

  • T <: A: 作用於 function, 約束:T是A的子類,也稱作upper type bound,這是一個協變。
    一般會和-T合用。
  • T >: A: 作用於 function, 約束:T是A的超類,也稱作lower type bound,這是一個逆變。
    一般會和+T合用。
  • T <& A: 作用於 function, 約束:存在一個T => A的implicit conversion,也稱作view bound.

<:, >:, <& 作用於泛型函數之間賦值。

請看不變(Invariant), 協變(Covarinat), 逆變(Contravariant) : 一個程序猿進化的故事

編譯.scala文件到jar文件

scalac -d test.jar D:\project\*

參照


免責聲明!

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



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