Scala模式匹配函数的第一个类型参数

时间:2014-04-11 07:46:19

标签: 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): 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)
  }
}

也许是抽象类型?

2 个答案:

答案 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

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