Table of contents


Scala IDE

  1. eclipse 3.7 (indigo)
  2. scala IDE plugin 2.9
  3. jdk 1.7.03

一切換到scala的環境,IDE就凍住了,用VirtualVM觀查的結果是執行scala的vm(不是ide本身的vm)的Permanent Generation Memory爆了,把它開到256M(-XX:MaxPermSize=256m)就不會一切到scala perspective,IDE就掛掉。

#utf8 (do not remove)
-startup
../../Common/plugins/org.eclipse.equinox.launcher_1.2.0.v20110502.jar
--launcher.library
../../Common/plugins/org.eclipse.equinox.launcher.i18n.win32.win32.x86_64_4.2.0.v201201111650
-showsplash
C:\Genuitec\Common\plugins\org.eclipse.platform_3.7.2.v201202080800\splash.bmp
--launcher.XXMaxPermSize
256m
--launcher.defaultAction
openFile
-install
C:\Genuitec\Profiles\scala
-configuration
C:\Genuitec\Profiles\scala\configuration
-vmargs
-Xms256m
-Xmx1024m
-XX:MaxPermSize=256m

  • scala是可自我成長的語言
  • scala混合了oo跟function lang
  • java中的static method可以考慮用function的方式實現,statistic method可視為一種退化的function lang?
  • scala是純oo lang,所有的東西都是物件,所有的操作(含運算子)都是method,所以,可以做運算子的override
  • scala可以與java無縫的整合,事實上,scala很多型號都是來自java。scala call java lib會很容易,但java call scala會有比較多的限制,因為scala的物件模型及語意比java豐富,java沒辦法一一對應。

  • scala有兩種變數
  1. expression後面的分號(;)可有可無
  2. val : 像java的final變數,一旦宣告後,就不能改變 (如果重新指派,會出reassignment的error)
  3. var : 像java的non final變數,可以重新指派值
  • scala的array跟java一樣是0-base但是,是透過()存取,而不是[]
method
def mymethod(x: Int, y: Int) : Int = {
  x + y
}

def mymethod(x: Int, y: Int) = x + y

所有的運算子在scala都是method,所以1 + 2是這樣的method call

(1).+(2)

1是物件,+是method name,1物件透過.來呼叫+method並傳入參數值2

以這樣的角度來看Array,Array就很直覺了,Array在Scala也只是一般的物件,而不是像java一樣,而不是像java一樣,是屬於語法等級的物件

foreach

for (arg ← args) println(arg)

function

function literal

單行

(x: Int, y: Int) => x + y 

多行時可以用大括號將 functio body括起來

(x: Int, y: Int) => {
    val z = x + 1
    z + y
}

這邊用function literal來達到foreach的功能,function literal有三種用法

第一種是最囉嗦,array的item要給型別而且給了型別,外面還要配一對括號

myarray.foreach((item: String) => println(item))

這個是比較正常的用法

myarray.foreach(item => println(item))

超精簡的用法,但只適用於只有一個參數的狀況

myarray.foreach(println)

function return type

為什麼sum function可以不用指定return type,而factorial必須指定return type為Int?

  def sum(a:Int,b:Int) = a+b
  def factorial(n:Int):Int = if (n==0) 1 else n * factorial(n-1)

因為在sum function中complier可以推斷(infer)出a + b的回傳值是Int型別,但在factorial中,回傳值可能是 1 或者是n * factorial(n-1), 而n * factorial(n-1)是未知型別,所以,我們必須指定return type,給complier一個提示。

有些語言的compiler可以由factorial function的第一個回傳值為1來推斷return type為Int,但scala的complier不行

operator notation
  1. infix 1 + 2
  2. prefix +1,-1, !foo, ~bar (只有+,-,!,~可以為prefix operator,定為方式為unary_+,unary_-,unary_!,unary_~,)
  3. postfix 1.toLong

functionN

package scala
 
 
trait Function2[@specialized(scala.Int, scala.Long, scala.Double) -T1, @specialized(scala.Int, scala.Long, scala.Double) -T2, @specialized(scala.Unit, scala.Boolean, scala.Int, scala.Float, scala.Long, scala.Double) +R] extends AnyRef { self =>
  /** Apply the body of this function to the arguments.
   *  @return   the result of function application.
   */
  def apply(v1: T1, v2: T2): R
 
  /** Creates a curried version of this function.
   *
   *  @return   a function `f` such that `f(x1)(x2) == apply(x1, x2)`
   */
  def curried: T1 => T2 => R = {
    (x1: T1) => (x2: T2) => apply(x1, x2)
  }
  @deprecated("Use 'curried' instead", "2.8.0")
  def curry = curried
 
  /** Creates a tupled version of this function: instead of 2 arguments,
   *  it accepts a single [[scala.Tuple2]] argument.
   *
   *  @return   a function `f` such that `f((x1, x2)) == f(Tuple2(x1, x2)) == apply(x1, x2)`
   */
  def tupled: Tuple2[T1, T2] => R = {
    case Tuple2(x1, x2) => apply(x1, x2)
  }
  override def toString() = "<function2>"
}
 
}

scala中的每個function,都是實作像上面的functionN(N從0~22)的trait,以(x: Int, y: Int) ⇒ x + y 來說,就是上例中的Function2[-T1, -T2, +R], 因為 (x: Int, y: Int) ⇒ x + y 就 傳入兩個int的參數並傳回一個int的結果,這樣與Function2的def apply(v1: T1, v2: T2): R是相等的。

closure

closure跟function literal語法很相似,但closure多了free variables,所以,free variables可被當做區分closure跟function literal的依據

free variables

TBC

Constructor

primary constructor
class MyClass(x: Int, y: Int)

auxiliary constructor
class MyClass(x: Int) {
    def this(x:Int) = this(x, 1) 
}

在scala,只有primary constructor可以呼叫super class的Constructor

 

function parameters

repeated parameters

repeated parameters像java的 myfunc(String… args),後面能用0到多個相同型別的參數

def myfunc(args: String*)

naming parameters

naming parameters主要是在使用functions時可以指定參數的名稱,也因為可以指定參數的名稱, 所以傳入的參數順序可以跟原來宣告時的不一樣

def myfunc(foo: Int, bar: String)
 
// call myfunc with naming parameter
val x = myfunc(bar="test", foo=1)

default value

參數的預設值,如果沒有特別指定時,參數會以預設值為準

def myfunc(foo: Int = 5)

loop

如while 或者是 do-while loop 都是會帶有副作用(side effect),請儘量改用其他的方式實作

for

for loop有filter的功能

val filesHere = (new java.io.File(".")).listFiles
for (file <- filesHere if file.getName.endsWith(".scala"))
  println(file)
 
// 上面那邊,的效果等同於  
for (file <- filesHere)
  if (file.getName.endsWith(".scala"))
    println(file)  

filter也可以累加,像這樣

for (
  file <- filesHere
  if file.isFile
  if file.getName.endsWith(".scala")
) println(file)

apply() and update()
()()=是語法糖(complier sugar),分別等效於apply()update() ()
apply() ()= : update()

Import and Package

pacakge
  1. 可以是 java style ,把 package name 放在最上面
  2. 可以是 c# like,用 com.kentchiu { package content } 或 com{ kentchiu { package content} }
  3. _root_ package
import

與 java 的不同

  1. 可以直接 import class member
  2. 可以 rename 或隱藏部份被 import 的 members
import com.kentchiu.{Foo, Bar}        // 只 import Foo 跟 Bar
import com.kentchiu.{Foo, Bar => Baz} // 只 import Foo 跟 Bar, Bar 改名為 Baz
import com.kentchiu.{Bar => _, _}     // Bar rename 成 _ ,會變成 import com.kentchiu 但把 Bar 排外

trait

Trait像是java的interface,不過,更像是ruby的mixin

Ordered Trait

Ordered Trait是用來說明trait一個很好的例子,Rubyer應該對這個例子很眼熟

case class

function programming

Functional programming is a programming paradigm that describes computation as the evaluation of mathematical functions avoiding state, mutual data and therefore side effects

Function programming based on applying functions to arguments in order to receive some desired values

The core idea for computation has shifted from a series of instructions (which specify precisely how the computation should proceed) to Notation of expressions, based on functions and values. You no longer have to follow a plan of instructions in order to understand a computation but decompose such an expression into its single elements.

Sequence Comprehensions

Tuple

scala> val t = (1,2)
t: (Int, Int) = (1,2)
 
scala> val t = new Tuple2(1,2)
t: (Int, Int) = (1,2)

tuple是透過特殊index語法存取

scala> t._1
res3: Int = 1
 
scala> t._2
res4: Int = 2

另外一種建立tuple的語法

scala> 1->2
res0: (Int, Int) = (1,2)

Extractors

利用 unApply() method搭配pattern match將資訊從class中萃取出來

Parser Combinators

Symbol Literals

Symbol Literals是在字串前加一個單引號’,像這樣’foo

Symbol Literal主要作用是用來當作識別用,可以視為一個字串,但它不同於字串的地方有

  1. 不可以有任何空白
  2. 一致性
  3. 對重構比較友善

像典型的map可以寫成這樣

"key" -> "value"

key的部份可以換成Symbol Literal取代

'key -> "value"

這樣的好處是,’key更能代表唯一性,而且,如果要進行重構,’key對於重構的支援會比”key”來的好,如果任何地方需要用字串當作識別的時侯,或者可以考慮換成用Symbol Literal取代

TBD

  • The Divide and Conquer principle
  • Implicit Conversions and Parameters

Resource