Archive

Posts Tagged ‘Scala’

Scala : Functions and Parameters

April 20th, 2010 leeing No comments

一个Function 是一个实例

在scala中,function是类的实例,所以在一个function上进行和类的实例一样的操作,下面创建了一个function并将它赋值给一个变量:

scala> val f:Int => String = x => "Dude: "+x
f: (Int) => String = <function1>

实际上它相当于:

scala> val f:(Int => String) = {  x=> "Dude :" +x }
f: (Int) => String = <function1>

可以在 f上调用方法:

scala> f.toString
res0: java.lang.String = <function1>

scala> f == f
res1: Boolean = true

scala> f == 4
res2: Boolean = false

用一个参数来apply function:

scala> f(44)
res3: String = Dude: 44

functions 作为参数传递

function能像任何其它参数那样被传递给方法。下面定义一个w42 方法,它接收一个输入为Int返回为String的function,在这里w42方法apply 42给函数,并返回結果。

scala> def w42(f: Int => String) = f(42)
w42: (f: (Int) => String)String

用函数变量来调用它:

scala> w42(f)
res11: String = Dude: 42

Read more…

Categories: Scala Tags:

Scala 集合框架:Tuple,Map[K,V],Option[T]

April 19th, 2010 leeing No comments

Tuple

Tuple 能让一个方法返回两个或三个值,例如下面的代码输入一个 List[Double],返回元素个数,元素的和及其平方和:

def sumSq(in: List[Double]): (Int, Double, Double) =
in.foldLeft((0, 0d, 0d))((t, v) => (t._1 + 1, t._2 + v, t._3 + v * v))

这里,编译器会将在括号中的集合元素看作是一个Tuple,上面的代码会翻译成:Tuple3[Int,Double,Double],这个函数接收两个参数:t和 v,t是一个Tuple3,而v是一个Double。
使用模式匹配可以让上面的代码更易理解:

def sumSq(in: List[Double]) : (Int, Double, Double) =
in.foldLeft((0, 0d, 0d)){
case ((cnt, sum, sq), v) => (cnt + 1, sum + v, sq + v * v)}

当然,也可以用其它方式来创建一个Tuple:

scala> Tuple2(1,2) == Pair(1,2)
scala> Pair(1,2) == (1,2)
scala> (1,2) == 1 -> 2

其中最后一种写法 1 -> 2 对于传递pairs 是很有用的一种方式。Pairs经常出现在代码中,包括用来创建 Maps 的 name/value 对。

对于Tuple元素的读取,应该使用下标 _n,例如 t._1, t._2 ,t._3 ,注意这里起始为1,并且对元素的引用不能越界。

Map[K,V]

Map 是一个 key/value 对的集合, key 是唯一的,但value 可以不唯一,Scala中的默认Map实现是不可变的,可以用于多线程环境,而且性能与Java中的HashMap相当。
创建一个 Map:

scala> var p = Map(1 -> "David", 9 -> "Elwood")
p: scala.collection.immutable.Map[Int,java.lang.String] = Map((1,David), (9,Elwood))

添加一个元素:

scala> p += 8 -> "Archer"

scala>  p = p + (9 -> "Archer")
p: scala.collection.immutable.Map[Int,java.lang.String] = Map(1 -> David, 8 -> Archer, 9 -> Archer)

如果想取出一个不存在的元素:

scala> p(88)
java.util.NoSuchElementException: key not found: 88

这里会抛出异常,虽然看起来并不方便,因为Java的Map能够通过返回null来处理这个情况,但这样做有两个缺点:首先,必须对每个Map的访问进行 null-test,其次,这代表着不能在一个Map中存储null值。对此Scala有一个更好的机制,即Map的get()方法将返回一个包含了結果的Option(Some 或none):

scala> p.get(88)
res10: Option[java.lang.String] = None

如果key没有找到,可以返回一个默认值:

scala> p.getOrElse(99, "Nobody")
res55: java.lang.String = Nobody
scala> p.getOrElse(1, "Nobody")
res56: java.lang.String = David

也可以使用flatMap来返回key在1-5之间的值:

scala> 1 to 5 flatMap(p.get)
res13: scala.collection.immutable.IndexedSeq[java.lang.String] = Vector(David)

注意,表面上来看这里p.get 只是一个方法,但是Scala正期待着一个拥有特定类型的参数,而你传递了一个接收一个参数的方法,这时Scala会将这个方法和它未写的参数提升为一个函数。

Read more…

Categories: Scala Tags:

Scala 集合框架:List

April 19th, 2010 leeing No comments

本文的示例代码来自 <Beginning Scala> ,由于Scala中的集合框架已经重写, 这里的代码输出都是在 Scala 2.8.0RC1 下运行得出的,跟原书中有一定的差距。

1. Range

collections 可以拥有任意数量的元素,或者局限于零个或一个元素(如 Option ),Collections 可以是strict 或是 lazy 的。Lazy Collection 可以拥有不消耗内存的元素,直到它们被访问。例如一个 Range 类:

scala> 0 until 10 by 3
res7: scala.collection.immutable.Range = Range(0, 3, 6, 9)

在这里,Range 中的元素在被访问之前并不会被实例化,下面代码只访问了前5个元素:

scala> (1 to Integer.MAX_VALUE - 1).take(5)
res8: scala.collection.immutable.Range = Range(1, 2, 3, 4, 5)

这个例子中不会消耗很多内存,因为只有需要的元素才被创建。

2. 构造一个列表

Collection 可能是可变的(即引用的内容可以被改变),也可能是不可变的(即一个引用所指向的东西不可以被改变),但注意的是不可变的Collections 可以包含可变的项目。

Scala 的list[T]是一个linked list 类型的T,代表它可以是任意类型的顺序列表。在内部,List 是由 :: 构造的, 即Scala 的 :: 类,例如:

scala> 1::2::3::Nil
res9: List[Int] = List(1, 2, 3)

实际上,它和下面的代码是相同的:

scala> new ::(1, new ::(2, new ::(3, Nil)))
res10: scala.collection.immutable.::[Int] = List(1, 2, 3)

3. 添加元素

:: 接收 head 为单个元素,而tail 则是另外一个 list , 其中 :: 左边的是 head,而 :: 右边则是tail。

也可以利用 apply 方法生成一个list :

def apply[T](param: T*)

添加一个元素:

scala> val x = List(1,2,3,4)
x: List[Int] = List(1, 2, 3, 4)
scala> 99::x
res12: List[Int] = List(99, 1, 2, 3, 4)

注意在这里 x 并没有改变,而是创建了一个有新的head 和老的tail 的list。这个过程是很快的,是一个复杂度为O(1)的操作。

4. 归并列表

可以归并两个列表从而生成一个新的List,这个操作也是O(n),其中 n 是第一个List中的元素的个数。

scala> val x = List(1,2,3)
scala> val y = List(99, 98, 97)
scala> x ::: y
res3: List[Int] = List(1, 2, 3, 99, 98, 97)

过滤filter:

scala> List(1,2,3).filter(x => x % 2 == 1)

Read more…

Categories: Scala Tags:

Scala : Option 和 foldLeft

April 18th, 2010 leeing No comments

下面这段代码来自Beginning Scala,它的主要功能是读取输入的字符串,把其中的数字字符串转为整数,并相加求和,很简单的一段代码,但包含了很多語法细节。

import scala.io._

def toInt(in: String): Option[Int] =
  try {
    Some(Integer.parseInt(in.trim))
  } catch {
    case e: NumberFormatException => None
  }
def sum(in: Seq[String]) = {
  val ints = in.flatMap(s => toInt(s))
  ints.foldLeft(0)((a, b) => a + b)
}

val lines = Seq("1","2","3","str")
println("Sum is :"+sum(lines))

在这里,首先看 Option[Int],Option是一个很有趣的容器,它只包含零个或一个元素,如果是零个元素,则类型为 None,None 是一个 singleton ; 如果拥有一个元素,则类型为 Some( theElement),Option的一个重要作用是避免了空指针异常和显式的null 测试,如果Option是None,则逻辑代码遍历的是零个元素;如果是Some,则逻辑代码只应用于一个元素。本例中如果输入的字符串不能转化为整数,会抛出异常并返回 None。

至于 Seq 则是一个trait,它被许多集合类所继承,是Array,List 及其它一些序列容器的 supertrait。trait 类似于java 中的interface,可以将多个trait融合到一个类中,但不同的地方是trait中可以有实现的方法。Trait不能接受构造方法参数,除此之外它的行为和类是大致相同的,它和interface一样,实现多重继承的同时也避免了菱形问题。

最后看这一行实现了求和的的函数代码:

ints.foldLeft(0)((a, b) => a + b)

在这里,foldLeft 接收一个seed 值 0,并且将函数应用于这个seed和序列ints中的第一个元素,然后它取应用了函数之后的计算結果和序列中的下一个元素进行函数计算,如此一直迭代,直到序列中没有元素为止。foldLeft在计算累积值时显得很有用,数学中sum,prod,min,max 函数等可以很容易地用foldLeft来进行实现。(a,b) =>a+b 则是定义了一个简单的函数,返回相加的和。注意这里没有为a和b 定义类型,因为Scala的编译器会自动推导它们都是Int类型。

从这个例子也可以看到 Scala 的函数代码相当简约的,一行代码有时候包含信息量也很大。

Categories: Scala Tags:

《Programming Scala》:Scala 的特性

January 27th, 2010 leeing 2 comments

本文是《Programming Scala》第一章的笔记,Scala 是一门很有趣也很简练的语言。

Scala为并行,简洁,可伸缩性而设计,它是一种函数式和面向对象的混合式语言,提供了基于actor的消息传递模型以去除并行带来的复杂性。使用这个模型,可以编写简洁的多线程代码(synchoroize关键字可以从词汇中消除了),而不用担心线程之间的数据连接以及处理锁和释放所带来的问题。

然而Scala也能用来编写单线程的应用程序,或者作为多线程应用的单线程模块,它的函数式风格有利于单线程和多线程的应用。Scala的并行模型与Erlang的风格很相似,但Scala的优点是:它是强类型而Erlang是弱类型,能在JVM上运行,与Java很好的进行交互。

下图展示了Scala在企业应用中适合的地方:

scala-in-enterprise

Scala in Enterprise Environment

注意到,可以将Java代码包装在Scala的actor库中提供线程的隔离,如果要在线程之间通讯,则使用Scala轻量级API来传递信息。在Scala中不用在创建线程时马上用同步来限制其并行,而是在不使用锁的情况下进行真正的并行操作,这就能更关注应用逻辑而不是低层次的线程。

Scala是静态类型的,但与Java 不同的是,不必明确反复地指定类型,很多情况下编译器可以进行类型推断,这一特性在简化函数的参数和返回值时很有用。

Scala的内核是很小的,其它包含操作符,Actor,都仅仅只是Scala库的一部份,可扩展性是极强,完全可以自行写一个实现。函数式编程是一种声明式的风格,在这种风格中指明的是“做什么”而不是“应该怎样做”,在XSLT,规则引擎,或者ANTLR中使用的就是函数式风格。

在一个数组中寻找最大值的函数式编程如下:

def findMax(temperatures : List[Int]) = {
	temperatures.foldLeft(Integer.MIN_VALUE) {
  		Math.max
	}
}

将列表中的每个元素乘以2:

val values = List(1, 2, 3, 4, 5)
val doubleValues = values.map( _ * 2)

计算一个数的阶乘:

def fact(n: Int) = 1 to n reduceLeft (_*_)

Read more…

Categories: Scala Tags: