Scala 中的钩子模式

发布于 2024-10-21 08:57:43 字数 217 浏览 1 评论 0原文

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

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

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

Scala 中有这样的钩子吗?

马蒂亚斯

I'm looking for a concise documentation of all hooks in Scala. A hook is any situation in the program flow where the common behavior can be intercepted. Such situations include:

  • declaration of classes or traits
  • access to methods and fields
  • mix-in of threads, inheritance

I'm coming from a Ruby background where, for example, method_missing allows to intercept non-existent method calls.

Are such hooks available at all in Scala?

Matthias

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

赏烟花じ飞满天 2024-10-28 08:57:43

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

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

There is no equivalent of method_missing in Scala 2.8 or earlier. In Scala 2.9 (under development), a Dynamic trait will be added. Unknown method calls to objects declaring the Dynamic trait will be automatically translated by the compiler to instead call invokeDynamic. The idea is to get some of the power of dynamically typed languages in a safe and sane way, without paying the performance overhead of dynamic typing if unneeded. It also simplifies interoperability issues when calling objects defined in dynamic languages from within Scala.

Other than that, hooking in new behaviour in Scala is largely done either via classic inheritance, or by addiing new functionality to objects via implicit conversions.

梦在深巷 2024-10-28 08:57:43

不,他们不是。在静态语言中,面向方面的编程可用于某些相同的目的。请参阅我可以在 Scala 中进行面向方面的编程吗?
但当然,“类或特征的声明”和“线程的混合、继承”不是控制流的一部分。如果你想拦截它们,你需要一个编译器插件。

No, they aren't. In static languages, aspect-oriented programming can be used for some of the same purposes. See Can I do Aspect Oriented Programming in Scala?
But of course, "declaration of classes or traits" and "mix-in of threads, inheritance" are not part of the control flow. If you want to intercept them, you'll need a compiler plugin instead.

等数载,海棠开 2024-10-28 08:57:43

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.

Scala tends to encourage the use of closures instead of the type of hooks you're talking about (most of which it can't implement conveniently due to static typing and compilation).

This requires you to know in advance where flexibility in the common behavior may be desired, but is very powerful and easy to use when it's available. For example, suppose you have a method that prints out people's names:

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.

but if you're really going to be changing name-printing a lot, you're better off building that in:

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.
满意归宿 2024-10-28 08:57:43

Scala 中没有这样的东西。

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

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

There is no such thing in Scala.

Or, to put it more precisely, static typing ensure we know what will happen at the time the code is compiled. Any such hook would change the behavior at run time, which would defeat the purpose of static typing.

One can modify the behavior at compile time, through compiler plugins, or even change stuff at class load time, through class loaders.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文