似乎类型类似乎是将操作应用于许多不同类型的标准。它不是在运行时查找方法(嗯,它可以,但不是纯模式),但它可以提供你想要的。
trait Numeric[T] {
def times(x :T, y : T) : T
}
object Numeric {
implicit val doubleNumeric = new Numeric[Double] {
def times(x : Double, y : Double) = x*y
}
implicit val intNumeric = new Numeric[Int] {
def times(x : Int, y : Int) = x*y
}
}
def square[A : Numeric](x : A) = implicitly[Numeric[A]].times(x,x)
如果您在 scala REPL 中执行此操作,请确保对象 Numeric 是 trait Numeric 的真正伴侣对象。您可以通过将声明包装在另一个对象(例如 tmp)中,然后导入 tmp._ 来做到这一点。
接下来,只需使用不同的值调用 square :
scala> square(2)
res6: Int = 4
scala> square(4.0)
res7: Double = 16.0
Scala 实际上提供了一个用于数值计算的 Numeric 类型类,参见:http ://www.scala-lang.org/api/current/scala/math/Numeric.html
我还写了一篇关于 Scala 中的类型类模式以及使用它来适应多个 API 或执行多个调度的方法:http:
//suereth.blogspot.com/2010/07/monkey-patching-duck-typing-and -type.html
如果你用谷歌搜索“scala type class”,你应该会看到很多信息。
第 2 部分 - 一个实际的 response_to?
如果你真的很想在 scala 中使用 respond_to,那么你有点 SOL。这是因为 respond_to 确实是一个动态概念。如果您尝试调用不存在的类上的方法,您正在定义将调用的类上的方法。Scala 不像某些动态 JVM 语言那样抽象方法调用。这意味着在方法调用中没有任何钩子可供您拦截和交互。你能做的最好的事情是一种接口适配形式,或者某种面向方面的编译后钩子来为你重写字节码。
我们可以利用一个神奇的部分,它也被用于一些 AOP 框架:动态代理。
scala> object AllPowerfulProxy extends InvocationHandler {
| def invoke(proxy : AnyRef, m : Method, args : Array[AnyRef]) : AnyRef = {
| println(" You really want to call " + m.getName + "?")
| null // Maliciously Evil!
| }
| }
defined module AllPowerfulProxy
scala> def spawn[A : Manifest] : A = {
| val mf = implicitly[Manifest[A]]
| java.lang.reflect.Proxy.newProxyInstance(mf.erasure.getClassLoader,
| Array(mf.erasure),
| AllPowerfulProxy).asInstanceOf[A]
| }
spawn: [A](implicit evidence$1: Manifest[A])A
现在我们可以使用它来将对象生成到任何接口。让我们看看我们能做些什么:
scala> val x = spawn[TestInterface]
You really want to call toString?
java.lang.NullPointerException
at scala.runtime.ScalaRunTime$.stringOf(ScalaRunTime.scala:259)
你看到我们在那里做了什么吗?当 REPL 尝试对表达式的结果调用 toString 时,它会在我们的动态代理上调用它。由于代理是一个占位符,实际调用委托给我们的 AllPowerfulProxy 类,如何打印消息:“你真的想调用 toString?”。然后 REPL 命中 null 返回并引发异常。您会看到,使用动态代理会将错误转移到运行时,因此您需要非常小心地实例化对象并返回正确的类型。根据系统的复杂性,您还应该担心类加载器。如果您曾经收到 Foo 到 Foo 的 ClassCastException,那么您就知道您正处于类加载器的地狱中。
无论如何,如果您对动态代理还有其他问题,请随时提出。在静态类型语言中,最好使用类型类并迁移到使用它们的设计模式,而不是使用 respond_to 的设计模式。(你会惊讶于你可以用类型类和类型系统完成什么)。