Scala中的钩子模式

时间:2011-03-09 07:00:47

标签: scala

我正在寻找Scala中所有钩子的简明文档。钩子是程序流程中可以截获常见行为的任何情况。这种情况包括:

  • 类别或特征的声明
  • 访问方法和字段
  • 线程混合,继承

我来自Ruby背景,例如,method_missing允许拦截不存在的方法调用。

Scala中是否提供了这样的钩子?

的Matthias

4 个答案:

答案 0 :(得分:7)

Scala 2.8或更早版本中没有等效的method_missing。在Scala 2.9(正在开发中)中,将添加动态特征。声明动态特征的对象的未知方法调用将由编译器自动翻译,而不是调用invokeDynamic。我们的想法是以安全和理智的方式获得动态类型语言的一些强大功能,而无需支付动态类型的性能开销(如果不需要的话)。当从Scala中调用动态语言中定义的对象时,它还简化了互操作性问题。

除此之外,在Scala中挂钩新行为主要通过经典继承或通过隐式转换向对象添加新功能来完成。

答案 1 :(得分:3)

不,他们不是。在静态语言中,面向方面的编程可用于某些相同的目的。见Can I do Aspect Oriented Programming in Scala? 但是,当然,“类或特性的声明”和“线程混合,继承”是不是控制流的一部分。如果你想拦截它们,你需要一个编译器插件。

答案 2 :(得分:3)

Scala倾向于鼓励使用闭包而不是你所讨论的钩子类型(由于静态类型和编译,大多数钩子无法很好地实现)。

这要求您事先知道可能需要的共同行为的灵活性,但是当它可用时非常强大且易于使用。例如,假设您有一个打印出人名的方法:

case class Name(first: String, last: String) {
  def title = last + ", " + first(0).toUpper + "."
}
trait Familiar extends Name {
  override def title = first + " " + last(0).toUpper + "."
}

def listing(names: Array[Name]) = names.foreach(name => println(name.title))

val jd1 = new Name("John","Doe)
listing(Array(jd1))  // Prints Doe, J.
val jd2 = new Name("John","Doe") with Familiar
listing(Array(jd2))   // Prints John D.

但是如果你真的要改变名字印刷,你最好在以下方面进行改造:

case class Name(first: String, last: String) {
  def title = last + ", " + first(0).toUpper + "."
}

def listing(names: Array[Name], address: Name => String = _.title) = 
  names.map(address).foreach(println)

val jd = new Name("John", "Doe")
listing(Array(jd))  // Uses default, so prints Doe, J.
listing(Array(jd), n => n.first + " " + n.last(0).toUpper + ".")  // Prints John D.

答案 3 :(得分:1)

Scala中没有这样的东西。

或者,更准确地说,静态类型确保我们知道在编译代码时会发生什么。任何这样的钩子都会改变运行时的行为,这会破坏静态类型的目的。

可以通过编译器插件修改编译时的行为,甚至可以通过类加载器修改类加载时的内容。