函数上的Scala模式匹配';s第一类型参数

函数上的Scala模式匹配';s第一类型参数,scala,pattern-matching,type-erasure,type-parameter,Scala,Pattern Matching,Type Erasure,Type Parameter,假设您在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): Uni

假设您在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)
  }
}

可能是抽象类型?

我想我用
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

如果有人有更好的解决方案,请告诉我:)

您可以使用typeclass执行此操作,那么不需要反射或类型标记:

  // 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没有有用的公共超类(我假设你不能简单地给它们一个!),typeclass模式允许我们在不修改原始类的情况下“附加”公共超特性(“特殊多态性”)


我们以后可以通过添加更多的typeclass实例来支持附加的案例(对于C、D等),而无需修改
handle()
方法。

是否可以更改
handle
的签名?改变
A
B
?看起来很整洁,我认为它的性能比反射更好。谢谢