Scala Tour – 精選

筆者作了一個學習Scala精彩特性的網站Scala-Tour。在學習Scala是時候,遇到不少使人激動的特性,主要函數式編程和併發。相比下Java已經老態龍鍾,步履躇跚。或許Scala不會成爲替代Java語言,但的確給後來者設立了標杆。因此作了這個網站,順着一個一個例子,由淺入深,由表及裏。逐漸學會Scala,儘管不會所以成爲一個熟練Scala的開發者,可是對函數式編程的也會至關了然。這篇文章精選了Scala-Tour上了一些章節,想快速瞭解的朋友能夠看看這篇文章,固然想詳細看就上上Scala-Tour吧。java

一、再也不須要Close

在Java裏面,使用完資源(文件句柄,數據庫鏈接)等以後,必須手動Close。不然發生泄漏後,程序只有被迫重啓。Scala能夠經過函數式實現自動close。react

import scala.reflect.io.File
import java.util.Scanner

def withScanner(f: File, op: Scanner => Unit) = {
    val scanner = new Scanner(f.bufferedReader)
    try {
        op(scanner)
    } finally {
        scanner.close()
    }
}

withScanner(File("/proc/self/stat"),
    scanner => println("pid is " + scanner.next()))

這個例子是從/proc/self/stat文件中讀取當前進程的pid。withScanner封裝了try-finally塊,因此調用者不用再close。git

二、按名稱傳遞參數

咱們熟悉的參數傳遞方式是按值傳遞。按名稱傳遞的方式,能夠理解爲直接傳遞參數名字,等到實際調用的時候,再去取值。在Java代碼中,每每充斥着if(log.isDebug()){log.debug(…)}這樣語句。以前的if調用是頗有必要的,由於在以後的debug語句中每每有字符串拼接的操做。在不須要打Log的時候,字符串拼接也有可能發生異常拋出。而Scala能夠經過按名稱傳遞解決這個問題,這樣就再也不須要if(log.isDebug())這樣的語句了。程序員

val logEnable = false

def log(msg: => String) =
    if (logEnable) println(msg)

val MSG = "programing is running"

log(MSG + 1 / 0)

三、鴨子類型

「走起來像鴨子,叫起來像鴨子,就是鴨子。」這個例子中使用{ def close(): Unit }做爲參數類型。所以任何含有close()的函數的類均可以做爲參數。這樣的作法比使用接口要好不少,由於能夠不引入任何依賴。這個withClose方法單獨編譯,隨處使用。github

def withClose(closeAble: { def close(): Unit }, op: { def close(): Unit } => Unit) {
    try {
        op(closeAble)
    } finally {
        closeAble.close()
    }
}

class Connection {
    def close() = println("close Connection")
}

val conn: Connection = new Connection()
withClose(conn, conn =>
    println("do something with Connection"))

四、Trait

Traits就像是有函數體的Interface,使用with關鍵字來混入。單個Traits就像是一塊樂高積木,一個插件。就像下面的JsonAble,當使用一個對象的時候,能夠隨時隨地把它插在他上面。這個對接就具有了toJson的能力。不用建立一個類,或者寫組合的代碼,很是乾脆。這樣也可使代碼有很高的正交性。再也不會爲了一個很小的需求,去修改一個被普遍使用的類。正則表達式

trait ForEachAble[A] {
  def iterator: java.util.Iterator[A]
  def foreach(f: A => Unit) = {
    val iter = iterator
    while (iter.hasNext)
      f(iter.next)
  }
}

trait JsonAble {
  def toJson() =
    scala.util.parsing.json.JSONFormat.defaultFormatter(this)
}

val list = new java.util.ArrayList[Int]() with ForEachAble[Int]
list.add(1); list.add(2)

println("For each: "); list.foreach(x => println(x))
//println("Json: " + list.toJson())

五、函數式真正的威力

經過將函數做爲參數,可使程序極爲簡潔。 函數式除了能簡化代碼外,更重要的是他關注的是Input和Output,函數自己沒有反作用。 就是Unix pipeline同樣,簡單的命令能夠組合在一塊兒。 List的filter方法接受一個過濾函數,返回一個新的List 若是你喜歡Unix pipeline的方式,你必定也會喜歡函數式編程。 這個例子是用函數式的代碼模擬「cat file | grep ‘warn’ | grep ’2013′ | wc」的行爲。相比於Ruby等動態語言,這威力來自於科學而不是魔法數據庫

val file = List("warn 2013 msg", "warn 2012 msg", "error 2013 msg", "warn 2013 msg")

println("cat file | grep 'warn' | grep '2013' | wc : "
    + file.filter(_.contains("warn")).filter(_.contains("2013")).size)

六、再見 NullException

每一個Java程序員都被NullException折磨過。由於Java中每一個對象均可能爲Null,因此要麼處處檢查null的問題,要麼處處try/cache。
Scala提供了Option機制來解決,代碼中不斷檢查null的問題。這個例子包裝了getProperty方法,使其返回一個Option。 這樣就能夠再也不漫無目的地null檢查。只要Option類型的值便可。使用pattern match來檢查是常見作法。也可使用getOrElse來提供當爲None時的默認值。給力的是Option還能夠看做是最大長度爲1的List,List的強大功能均可以使用。
不是每一個對象均可覺得Null了,只有Option能夠爲None。這樣的作法顯示區分了可能爲Null的狀況,能夠和NullException說再見了。編程

def getProperty(name: String): Option[String] = {
  val value = System.getProperty(name)
  if (value != null) Some(value) else None
}

val osName = getProperty("os.name")

osName match {
  case Some(value) => println(value)
  case _ => println("none")
}

println(osName.getOrElse("none"))

osName.foreach(print _)

七、並行集合

這個例子是訪問若干URL。但確能夠並行訪問,比非並行的作法能夠快一倍。要想讓訪問並行,只要調用List.par就能夠了。json

val urls = List("http://scala-lang.org",
  "https://github.com/yankay/scala-tour")

def fromURL(url: String) = scala.io.Source.fromURL(url)
  .getLines().mkString("\n")

val t = System.currentTimeMillis()
urls.par.map(fromURL(_))
println("time: " + (System.currentTimeMillis - t) + "ms")

是否是很是的簡單?並行集合支持大部分集合的功能。不增長程序複雜性,卻能大幅提升併發的能力。bash

八、遠程Actor

Actor是併發模型,也使用於分佈式。這個例子建立一個時間服務器,經過alive來監聽TCP端口,register來註冊本身。調用時經過select建立client。其他使用方式和普通Actor同樣。
將單機併發和分佈式抽象成一種模型。簡化了程序複雜性。雖然多核編程並不普遍,但調用外部接口的狀況愈來愈多。Actor模型很是適用於這樣的異步環境。

import scala.actors.remote.RemoteActor._
import scala.actors.Actor._
import scala.actors.remote.Node

val port = 31241

val echoServer = actor {
  alive(port)
  register('echoServer, self)
  loop {
    react {
      case msg => {
        reply("replay " + msg)
      }
    }
  }
}

val timeServerClient = select(Node("127.0.0.1", port), 'echoServer)

timeServerClient !? "hi" match {
  case replay: String => println(replay)
}

九、抽取器

抽取器能夠進行解構。這個例子是構建一個Email抽取器,只要實現unapply函數就能夠了。
Scala的正則表達式會自帶抽取器,能夠抽取出一個List。List裏的元素是匹配()裏的表達式。
抽取器頗有用,短短的例子裏就有兩處使用抽取器:

  • 經過 case user :: do main :: Nil 來解構List
  • 經過 case Email(user, domain) 來解構Email。
import scala.util.matching.Regex

object Email {
  def unapply(str: String) = new Regex("""(.*)@(.*)""")
    .unapplySeq(str).get match {
    case user :: domain :: Nil => Some(user, domain)
    case _ => None
  }
}

"user@domain.com" match {
  case Email(user, domain) => println(user + "@" + domain)
}

十、DSL

DSL是Scala最強大武器,可使一些描述性代碼變得極爲簡單。這個例子是使用DSL生成JSON。Scala不少看似是語言級的特性也是用DSL作到的。
本身編寫DSL有點複雜,但使用起來很是方便。這樣可使Scala能夠嵌入XML,嵌入Json,嵌入SQL。而其餘語言中這些都只是字符串而已。

import org.json4s._
import org.json4s.JsonDSL._
import org.json4s.jackson.JsonMethods._
import java.util.Date

case class Twitter(id: Long, text: String, publishedAt: Option[java.util.Date])

var twitters = Twitter(1, "hello scala", Some(new Date())) ::
  Twitter(2, "I like scala tour", None) :: Nil

var json = ("twitters"
  -> twitters.map(
    t => ("id" -> t.id)
      ~ ("text" -> t.text)
      ~ ("published_at" -> t.publishedAt.toString())))

println(pretty(render(json)))

十一、Simple Build Tool

SBT是Scala的最佳編譯工具,在他的幫助下,你甚至不須要安裝除JRE外的任何東西,來開發Scala。
例如你想在本身的機器上執行Scala-Tour,能夠執行下面的命令

#Linux/Mac(compile & run):
git clone https://github.com/yankay/scala-tour-zh.git
cd scala-tour-zh
./sbt/sbt stage
./target/start

#Windows(can only compile):
git clone https://github.com/yankay/scala-tour-zh.git
cd scala-tour-zh
sbt\sbt stage

十二、結語

這幾個例子精選自Scala-Tour,這個網站中還有介紹了不少其餘好的特性,好比模式匹配和隱式轉換,就不逐一介紹了。這個項目Host在GitHub上,若是你也有精彩的用法的話,你們交流交流吧。

Refer:

[1] Scala Tour – 精選

http://blog.sae.sina.com.cn/archives/1199

http://www.yankay.com/scala-tour-choiceness/

[2] 函數式編程聖經

http://bit.ly/2rA5l8d

[3] scala 入門到精通

https://yq.aliyun.com/topic/69?utm_content=m_17543

[4] Scala語法技巧總結

https://weibo.com/ttarticle/p/show?id=2309404376256631189946

相關文章
相關標籤/搜索