文章出處

最近開始系統性的學習scala。其實之前使用過scala的,比如我在用Gatling這款性能測試工具的時候就接觸到了scala了。Gatling本身就是用Scala寫的,而且Gatling的性能測試配置文件本身就是一個scala類,可以隨意使用scala甚至是Java提供的各種類庫。當時覺得用Gatling特別舒服的原因就在于配置文件強大的表現力。而這種表現力就是由Scala語言提供的。

言歸正傳,學習Scala還是從最簡單的Hello world開始。在Scala官網中顯著的標題就是:

Object-Oriented Meets Functional

Have the best of both worlds. Construct elegant class hierarchies for maximum code reuse and extensibility, implement their behavior using higher-order functions. Or anything in-between.

從中可以看出Scala結合了面向對象及函數式編程這兩種編程范式。在本文中我將會拿Java語言和其比較,看看到底Scala強在那里。

使用Java語言實現一個Hello World的代碼如下:

1
2
3
4
5
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

以下是Scala的實現:

1
2
3
4
5
object HelloWorld  {
  def main(args: Array[String]): Unit = {
    println("Hello, World!")
  }
}

好吧,如果標點符號不算代碼行,Java版本和Scala版本的實現的代碼行數是一致的。貌似Scala并沒有減少什么。唯一減少的就在于println不用指定類名,以及對main方法不用聲明為static。

在這里對Scala實現與Java實現的幾個不同之處做個介紹。

  • 第一是Scala對HelloWorld的修飾符使用的是object。其實Scala中也有class關鍵字,那么object關鍵字和class關鍵字有什么區別那?簡單來說object關鍵字定義了一個匿名類,并且創建了該匿名類的單個實例(采用單例模式),該實例名為HelloWorld。所以object中定義的方法自動都是static的。我覺得object關鍵字存在的價值之一就是建立起了面向對象和函數式的橋梁。因為在面向對象的系統中,所有方法都必須存在于類中,而函數式編程中沒有類的概念,使用函數無需new類的實例,所以object中的方法都是靜態方法,可以直接被調用。進一步解讀請到這里

  • 第二是Scala中對變量的類型的定義方式是變量名在前,類型在后,中間用冒號相隔。原因之一是代碼更可讀。因為我們更關心變量名,而類型其次,尤其是你擁有一個超級長的類型的情況下(比如 HashMap<Shape, Pair<String, String>>);原因之二據說是這樣的方式在實現Scala類型時技術上要簡單些。進一步解讀請到這里

  • 第三是main函數的返回值是Unit,而不是Java中的Void。為什么是這樣那?我想是因為Scala為了實現自己的類型系統,對于無顯式返回值的函數直接使用Void是不合適的。在Scala.Unit文檔中是這樣定義Unit的:

Unit is a subtype of scala.AnyVal. There is only one value of type Unit, (), and it is not represented by any object in the underlying runtime system. A method with return type Unit is analogous to a Java method which is declared void.

  • 第四是Scala中表達式最后的分號是可選的。原因就是為了契合函數式編程的哲學,即一切盡可能的簡單。不寫分號程序員一天可以多敲一些代碼出來。

好吧,其實在Scala中Hello World還有一種寫法。

1
2
3
object HelloWordV2 extends App {
  println("Hello, World!")
}

代碼從三行減少到了兩行,Scala終于勝出了。那么App是個什么鬼?App是一個trait。trait又是什么鬼?trait是Scala中的一個特殊類型,它與Java中的interface很相似,但比interface強大。HelloWordV2添加了對App的擴展后,就自動成為了一個可以運行的程序,由于App中定義了main方法,所以HelloWorldV2中就無需再定義了,牛逼的地方在于HelloWorldV2的body中的代碼都會作為main方法中的代碼被執行。以下是App源碼中對main方法的定義:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@deprecatedOverriding("main should not be overridden", "2.11.0")
def main(args: Array[String]) = {

this._args = args

for (proc <- initCode) proc()

if (util.Properties.propIsSet("scala.time")) {

val total = currentTime - executionStart

Console.println("[total " + total + "ms]")

}

看來App在實現main方法時還設置了一個計時器,通過scala.time這個屬性來開關。所以沒事翻翻源碼還是挺好玩的。

不知有沒注意到其實main方法是有個叫args的參數的,那么新版HelloWorld中如何使用該參數那?直接使用它就行。

1
2
3
object HelloWordV2 extends App {
  println("Hello, World!" + args(0))
}

ok,Scala版的Hello World就到這里吧。


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()