专注于快乐的事情

Scala的高级特性

本文于1500天之前发表,文中内容可能已经过时。

惰性求值

for 推导式(for comprehension)
隐式类(Implicit Classes)
=>

隐式转换

使用隐式能够减少代码,能够向已有类型中注入新的方法,也能够创建领域特定语言(DSL)。
implicit 可分为:
隐式参数
隐式转换类型
隐式调用函数

隐式参数

当我们在定义方法时,可以把最后一个参数列表标记为implicit,表示该组参数是隐式参数。一个方法只会有一个隐式参数列表,置于方法的最后一个参数列表。如果方法有多个隐式参数,只需一个implicit修饰即可。 当调用包含隐式参数的方法是,如果当前上下文中有合适的隐式值,则编译器会自动为改组参数填充合适的值。如果没有编译器会抛出异常。

def calcTax(amount: Float)(implicit rate: Float): Float = amount * rate
implicit val currentTaxRate = 0.08F
val tax = calcTax(50000F) // 4000.0

隐式地转换类型

使用隐含转换将变量转换成预期的类型是编译器最先使用 implicit 的地方。这个规则非常简单,当编译器看到类型X而却需要类型Y,它就在当前作用域查找是否定义了从类型X到类型Y的隐式定义
例子:

scala> val i: Int = 3.5 //直接报错
加上这句:
scala> implicit def double2Int(d: Double) = d.toInt
再运行,没报错
scala> val i: Int = 3.5 //i=3

Scala支持这种隐式转换,定义转换函数后, 编译器就会自动调用上面的转换函数, 将Double转化为Int

隐式调用函数

式调用函数可以转换调用方法的对象,比如但编译器看到X .method,而类型 X 没有定义 method(包括基类)方法,那么编译器就查找作用域内定义的从 X 到其它对象的类型转换,比如 Y,而类型Y定义了 method 方法,编译器就首先使用隐含类型转换把 X 转换成 Y,然后调用 Y 的 method。

class SwingType{
  def  wantLearned(sw : String) = println("兔子已经学会了"+sw)
}
object swimming{
  implicit def learningType(s : AminalType) = new SwingType
}
class AminalType
object AminalType extends  App{
  val rabbit = new AminalType
  rabbit.wantLearned("breaststroke")         //蛙泳
}

编译器在rabbit对象调用时发现对象上并没有wantLearning方法,此时编译器就会在作用域范围内查找能使其编译通过的隐式视图,找到learningType方法后,编译器通过隐式转换将对象转换成具有这个方法的对象,之后调用wantLearning方法

模式匹配(pattern matching)

scala语言里的模式匹配类似java语言中switch语句

使用match

val times = 1
times match {
  case 1 => "one"
  case 2 => "two"
  case _ => "some other number"
}

一个复杂的例子

for {
  x <- Seq(1, 2, 2.7, "one", "two", 'four)                           // <1>
} {
  val str = x match {                                                // <2>
    case 1          => "int 1"                                       // <3>
    case i: Int     => "other int: "+i                               // <4>
    case d: Double  => "a double: "+x                                // <5>
    case "one"      => "string one"                                  // <6>
    case s: String  => "other string: "+s                            // <7>
    case unexpected => "unexpected value: " + unexpected             // <8>
  }
  println(str)                                                       // <9>
}

匹配其他任意输入,x 的值被赋给 unexpected 这个变量。由于未给出任何类型说明,unexpected 的类型被推断为 Any,起到了 default 语句的功能。

for {
  x <- Seq(1, 2, 2.7, "one", "two", 'four)
} {
  val str = x match {
    case _: Int | _: Double => "a number: "+x
    case "one"              => "string one"
    case _: String          => "other string: "+x
    case _                  => "unexpected value: " + x
  }
  println(str)
}

在try-catch-finally语法中通过模式匹配

try {
  remoteCalculatorService.add(1, 2)
} catch {
  case e: ServerIsDownException => log.error(e, "error.")
} finally {
  remoteCalculatorService.close()
}

Case Class

首先case class是用于让你更加简洁的使用pattern matching, 如果你想对一个class进行pattern matching, 最好在前面加上case。

case 关键字的另一个特征便是让编译器自动为我们生成许多方法,其中包括了类似于 Java 语言中 String、equals 和 hashCode 方法。默认是可以序列化的,也就是实现了Serializable。

编译器同时会生成一个伴生对象(companion object),伴生对象是一个与 case 类同名的单例对象

伴生对象中已经自动添加了不少方法,apply 方法便是其中之一。该方法接受的参数列表与构造函数接受的参数列表一致。

因为有伴生对象,所以初始化的时候可以不用new。
case class User(name:String,age:Int)
val user = User("ww",30)

case class构造函数的参数是public级别的,我们可以直接访问
user.name

参考例子

case class Person(name : String,age : Int)

object ConstructorPattern{
    def main(args:Array[String]) :Unit = {
      val p = new Person("nyz",27)
      def constructorPattern(p : Person) = p match {
        //构造器模式必须将Person类定义为case class,否则需要自己定义伴生对象并实现unapply方法。
        case Person(name,age) => "name =" + name + ",age =" + age    
        //case Person(_,age) => "age =" + age
        case _ => "Other"
      }
      println(constructorPattern(p))
    }
}

http://www.cnblogs.com/zlslch/p/6115392.html

偏函数

Scala中的Partial Function就是一个“残缺”的函数,就像一个严重偏科的学生,只对某些科目感兴趣,而对没有兴趣的内容弃若蔽履。Partial Function做不到以“偏”概全,因而需要将多个偏函数组合,最终才能达到全面覆盖的目的。所以这个Partial Function确实是一个“部分”的函数。

型变

假设一个方法带有的参数类型为 List[AnyRef],你可以传入 List[String] 吗?换句话说,List[String] 是否应该被看作是 List[AnyRef] 的一个子类型呢?如果是,这种转化称为协变(covariance)。

型变在scala中灵活的分为了不变,逆变和协变。
如果某类型可以强制转换为子孙类,我们称为协变(+T 或? extends T),如果某类型可以强制转换为祖先类,我们称为逆变(-T 或? super T)。如果某类型完全不能被强制转换,就称为不变(Invariance)。

“+”表示协变,而“-”表示逆变
C[+T]:如果A是B的子类,那么C[A]是C[B]的子类(协变)。
C[-T]:如果A是B的子类,那么C[B]是C[A]的子类(逆变)。
C[T]:无论A和B是什么关系,C[A]和C[B]没有从属关系。

type 成员的工作机制与参数化类型中的类型参数非常类似

https://my.oschina.net/xinxingegeya/blog/486671
http://hongjiang.info/scala-covariance-and-contravariance/
http://lib.csdn.net/article/scala/25849

正则表达式

三重双引号来表示正则表达式字符串

参考网站

评论系统未开启,无法评论!