Кажется, что классы типов являются стандартом применения операции ко многим различным типам.Это не поиск методов во время выполнения (ну, это возможно, но не чистый шаблон), но он может обеспечить то, что вы хотите.
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 является истинным сопутствующим объектом для черты Numeric.Вы можете сделать это, обернув объявление в другой объект, скажем, tmp, а затем импортировав tmp ._.
Далее, просто вызовите квадрат с другими значениями:
scala> square(2)
res6: Int = 4
scala> square(4.0)
res7: Double = 16.0
Scala фактически предоставляетКласс числового типа для использования в числовых вычислениях, см .: 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
Если вы ищете Google для «класса типа Scala», вы должны увидеть много информации.
Часть # 2 - фактический response_to?
Если вы действительно хотели response_to в scala, вы в некотором роде SOL.Это потому, что response_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 тогда достигает нулевого возврата и выдает исключение.Видите ли, использование динамических прокси перемещает ошибки во время выполнения, поэтому вам нужно быть очень осторожным при создании объектов и возвращении правильных типов.В зависимости от сложности вашей системы вы должны также беспокоиться о загрузчиках классов.Если вы когда-нибудь получите ClassCastException от Foo для Foo, то вы знаете, что попали в ад загрузчика классов.
В любом случае, если у вас есть другие вопросы по динамическим прокси, не стесняйтесь их задавать.В статически типизированных языках вам, вероятно, лучше использовать классы типов и переходить к разработке шаблонов, используя их вместо тех, которые используют response_to.(Вы будете удивлены, что вы можете сделать с помощью классов типов и системы типов).