假设您在Scala中有这样的方法定义:
def handle[T](fn: T => Unit): Unit
是否可以对函数参数T
的类型进行模式匹配,以根据T的类型调用不同的方法?
您是否需要重新编写代替Function1
而不是模式匹配?
我尝试过以下操作但由于类型擦除而无效:
class A {
def x(fn: A => Unit): Unit = fn(this)
}
class B {
def y(fn: B => Unit): Unit = fn(this)
}
def handle[T](fn: Function1[T, Unit]): Unit = {
fn match {
case fnA: Function1[A, Unit] =>
new A().x(fnA)
case fnB: Function1[B, Unit] =>
new B().y(fnB)
}
}
也许是抽象类型?
答案 0 :(得分:1)
您可以使用类型类,然后不需要反射或类型标记:
// Typeclass defines things that can be handled
trait Handleable[T] {
def handle(fn: T => Unit)
}
// Two typeclass instances, one for A and one for B
implicit object AHandleable extends Handleable[A] {
def handle(fn: A => Unit) = new A().x(fn)
}
implicit object BHandleable extends Handleable[B] {
def handle(fn: B => Unit) = new B().y(fn)
}
// implicitly grab the instance for whichever type we are using (A, B...)
def handle[T](f: T => Unit)(implicit h: Handleable[T]) = h.handle(f)
//or equivalently:
//def handle[T: Handleable](f: T => Unit) = implicitly[Handleable[T]].handle(f)
handle((a: A) => println(a)) //> A
handle((b: B) => println(b)) //> B
由于A和B没有有用的常用超类(我假设你不能简单地给它们一个!)类型类模式允许我们“修改”一个普通的超级类而不修改原始类(“ad-hoc多态性” “)。
我们以后可以通过添加更多类型类实例来支持其他情况(对于C,D等),而无需修改handle()
方法。
答案 1 :(得分:0)
我想我找到了使用TypeTag
个实例的答案:
import scala.reflect.runtime.universe._
class A {
def x(fn: A => Unit): Unit = fn(this)
override def toString = "A"
}
class B {
def y(fn: B => Unit): Unit = fn(this)
override def toString = "B"
}
def handle[T : TypeTag](fn: Function1[T, Unit]): Unit = typeOf[T] match {
case t if t =:= typeOf[A] => new A().x(fn.asInstanceOf[Function1[A, Unit]])
case t if t =:= typeOf[B] => new B().y(fn.asInstanceOf[Function1[B, Unit]])
}
handle[A] { a: A =>
println("It's " + a)
}
handle[B] { b: B =>
println("It's " + b)
}
打印预期输出:
It's A
It's B
如果有人有更好的解决方案,请告诉我:)