Scala: 感觉像动态的静态语言

11-06-14 banq
Weblogs Forum - Scala: The Static Language that Feels Dynamic

著名的"Thinking in Java"作者Bruce Eckel 在artima.com写了这篇Scala入门篇(banq:artima的论坛和Jdon的论坛都源于同一个宗主Jive,所以你觉得两者界面很象)。

下面大概意译一下Bruce Eckel这篇文章:

Bruce Eckel 认为scala虽然是静态语言,但感觉非常像Python,

(Bruce Eckel用语很感性,不象Thinking,而象feeling)。

class Building
val b = new Building
<p>

val是不可变量,这样能够使得并发编码更容易一些(var也有变量的).这里没有必要在b之前象Java那样声明一下类型,因为scala能够分辨出类型。

class Building(feet: Int) {
  val squareFeet = feet
}
val b = new Building(100)
println(b.squareFeet)
<p>

println打印输出不必使用类似Java的System.out了,类中字段缺省是public的,这样我们可以使用b.squareFeet直接访问其类中字段。当然你也可以设置private。

class Building(val feet: Int)
val b = new Building(100)
println(b.feet)
<p>

这段和上面区别是b.feet, feet能够自动成为类的字段。

case class Building(feet: Int)
val b = Building(100)
println(b) // Result: Building(100)
<p>

这段代码主要是开始的case class ,参数自动成为字段,参数之前也不用加val了。

val m = Map(Building(5000) -> "Big", Building(900) -> "Small", Building(2500) -> "Medium")
m(Building(900)) // Result: Small
<p>

scala中使用->来表示map的键和值。

class House(feet: Int) extends Building(feet)
val h = new House(100)
println(h.feet) // Result: 100
<p>

展示了extends继承,但是注意extends后面的父类写法。

trait Bathroom
trait Kitchen
trait Bedroom {
  def occupants() = { 1 }
}
class House(feet: Int) extends Building(feet) with Bathroom with Kitchen with Bedroom
var h = new House(100
val o = h.occupants()
val feet = h.feet
<p>

traits是将行为混合在一起,类似过去的AOP等,被认为用来实现DCI架构较好的语言方式,这里的trait非常类似Java中的接口,但比接口要丰富,可以自己定义方法occupants,其def是用来定义方法名称的,等于号后面是方法体。

def occupants() = { 1 }表示返回值int类型1,如果要更加规范如下:

def occupants(): Int = { 1 }

注意occupants已经成为House的一部分,这就是traits的mixin力量,而且这个mixin的性能要比Java好多。

以上是简单的语法。

函数编程方式functional programming

比如我们有一个集合数据:

val v = Vector(1.1, 2.2, 3.3, 4.4)
<p>

通过下面语法可以输出打印:

for(n <- v) {

println(n)

}

注意:<- 前面的n能够得到v集合中每个值。

还有更简单的:v.foreach(println) (Java中参数一般是变量,不会是方法等,这里是方法println)

别看这么简单,它是利用的函数编程的优点,实际是一个匿名函数,完整的基本形式:

( function parameters ) => function body
<p>

=>意味着:将左边的参数应用到右边的代码中。

另外一个匿名函数案例:

(x:Int, y:Double) => x * y

之前的foreach ,实际完整的如下:

v.foreach((n:Double) => println(n))

通常情况下,scala能够看到v中的值类似是Double,因此可以简化如下:

v.foreach((n) => println(n))

如果你只有一个参数,忽略括号

v.foreach(n => println(n))

如果你只有一个参数,还可以将节省参数,用下划线替代:

v.foreach(println(_))

最后,如果函数方法只是调用一个其他方法,而且那个方法只使用一个参数,最后可以成为:

v.foreach(println)

可惜,foreach 有副作用,它不能返回任何值,大部分情况我们需要操作一个collection,并且返回值,然后,在这个返回结果上做一些操作(map/reduce),那么使用map,注意它不是数据结构Map。

v.map(n => n * 2)

将v中每个值乘以2,然后返回结果:

Vector(2.2, 4.4, 6.6, 8.8)

简写如下:

v.map(_ * 2)

还有其他操作方法:

v.reverse
v.sum
v.sorted
v.min
v.max
v.size
v.isEmpty
<p>

v.permutations 是产生一个遍历指针iterator

v.permutations.foreach(println).

另外有用功能是zip,可以把两个集合合并在一起:

Vector(1,2,3).zip(Vector(4,5,6))

结果是:

Vector((1,4), (2,5), (3,6))

v.zip(v.map(_ * 2))结果是:

Vector((1.1,2.2), (2.2,4.4), (3.3,6.6), (4.4,8.8))

匿名函数非常简单易用,但是如果你觉得难以理解,那么可以使用标准函数:

def timesTwo(d: Double) = d * 2

v.zip(v.map(_ * 2))就变为:v.zip(v.map(timesTwo))

模式匹配

trait Color
case class Red(saturation: Int) extends Color
case class Green(saturation: Int) extends Color
case class Blue(saturation: Int) extends Color

def matcher(arg:Any): String = arg match {
  case "Chowder" => "Make with clams"
  case x: Int => "An Int with value " + x
  case Red(100) => "Red sat 100"
  case Green(s) => "Green sat " + s
  case c: Color => "Some Color: " + c
  case w: Any => "Whatever: " + w
  case _ => "Default, but Any captures all"
}

val v = Vector(1, "Chowder", Red(100), Green(50), Blue(0), 3.14)
v.foreach(x => println(matcher(x)))
<p>

(banq注:在Java中大概要使用visitor模式来实现,复杂些)

match语法类似Java的switch 。但是break不是必须的。

case class对于模式匹配特别有用,因为可以分解它。Any是所有对象的根class,类似Java中的primitive类型,

Actor并发模型

这个在jdon已经讨论过多次,是一种Actor模型,通过异步消息通讯,可异步并发。要比Java多线程模型并发性能更好,彻底杜绝了共享锁。

// Bunnies.scala (Run as script: scala Bunnies.scala)
case object Hop
case object Stop

case class Bunny(id: Int) extends scala.actors.Actor {
  this ! Hop // Constructor code
  start()    // ditto
  def act() {
    loop {
      react {
        case Hop =>
          print(this + " ")
          this ! Hop
          Thread.sleep(500)
        case Stop =>
          println("Stopping " + this)
          exit()
      }
    }
  }
}

val bunnies = Range(0,10).map(new Bunny(_))
println("Press RETURN to quit")
readLine
bunnies.foreach(_ ! Stop)
<p>

(banq注:看到这段感觉很象Java的线程类,是不是可以改造一下呢)

act()方法是一个自动的 match方式,loop{ react{看上去怪,但是scala的关键,开始你能使用loop来打开邮箱消息的match状态,它实际是一个协调的多任务,每个任务做点事情然后放弃控制权,让下一个任务,这种方式好处没有共享内存,因此可以拓展伸缩,可以达数百万个任务。

注意class Benny开始两行:

this ! Hop

start()

scala不能在方法内进行对象初始化,放到方法之外,类中,!感叹号是发送消息,然后调用start()开始消息不断循环检查。

以上是Scala主要特征,本人看下来感觉是简单些,特别在了解了函数编程和Actors这两个主要编程范式和思想,我在Jdon其他帖子花过大量时间来讨论,有人感觉Scala复杂,可能是因为开始被误导?实际Scala比较简单强大。

                   

9
banq
2011-06-14 17:01
当思想已至,语言只是结果。

相关文章:

Google 推出 C++ Go Java Scala的基准性能测试

banq
2011-06-21 11:47
Programming in Scala, First Edition Scala编程第一版在线英文

另外一篇文章Scala的问题

blog:scala_problems [kotek.net]

作者使用了18个月的Scala,发现其问题如下:

1.编译速度, 相当慢,200多个类花费2分钟。

2.增量编译还没有,Eclipse等能够立即对类型等报错。Scala这方面还落后于Java

3.发布的jar变得巨大

4.不再可能返回java

5.二进制不兼容,2.7, 2.8 and 2.9彼此不兼容

6.Bugs and release cycle,作者每4个月总能发现新BUG,没有Java成熟

7.没有紧密的Loop循环,for(i <- 0 until 100){}将创建大量对象。

8.其实不是真正的Actor模型,Scala被业外人士奉为Actors模型的神物,业内却很少谈。 作者认为,Scala只是让他写出更好的Swing代码, 与JDBC更紧密整合, 做更多更好的XML处理, 进行Android编程。

[该贴被banq于2011-07-09 08:04修改过]

2gua
2013-01-20 17:22
语言的纷争永远是无止境,找准自己的那一个就好,我还是蛮喜欢Scala。

猜你喜欢