我想在Function1或PartialFunction上定义一个扩展函数。
我想这样做,因为我有一个类似于以下的用例:
class A
class B extends A
def foo(fun: Function[B, A]) = {
bar(fun.widen[A])
}
def bar(pf: PartialFunction[A, A]) = ???
从上面可以看出,为了实现这一点,我想到了定义这样一个扩展函数:
implicit class AugmentedFunction[T, U](fun: T => U) {
def widen[T1 >: T]: PartialFunction[T1, U] = { case t: T => fun(t) }
}
但不幸的是,由于擦除,这不起作用。我试着使用TypeTags,但我似乎无法以满足编译器的方式表达这一点。
澄清: 当我说它不起作用时,我的意思是它在使用时会引发异常(请参阅ScalaKata代码片段),它实际上不应该抛出异常并在ScalaKata上的代码片段的特定情况下打印“未定义”。
我的问题:
我怎样才能正确解决这个问题? Scalaz或Shapeless中是否已存在我不知道的功能?首先要做到这一点是否有意义?
以下是包含所有代码的代码段:http://www.scalakata.com/527bb729e4b0b1a1c4db1a73
答案 0 :(得分:3)
我认为你可以用课堂清单来做到这一点:
implicit class AugmentedFunction[T, U](fun: T => U)(implicit m: Manifest[T]) {
def widen[T1](implicit m1: Manifest[T1]): PartialFunction[T1, U] = {
case a if(m <:< m1) => fun(a.asInstanceOf[T])
}
}
class A
class B extends A
class C
val theFun: B => A = (b: B) => b
theFun.widen[A].isDefinedAt(new B) // true
theFun.widen[C].isDefinedAt(new C) // false
答案 1 :(得分:0)
错误说明了一切:java.lang.ClassCastException: ScalaKata$A$1 cannot be cast to ScalaKata$B$1
。基本上,当您调用foo( (a: B) => new A, new A)
时,A
值将传递给lambda,该lambda实际上接受类型B
作为param,因此从A
转换为B
时会出现异常因为不可能从泛型转换为特定的。
你必须使用类似的东西:
foo( (a: Ai) => new Ai, new Ai)
foo( (a: Ci) => new Ai, new Ci)
foo( (a: Ai) => new Ai, new Bi)
基本上,第二个参数应该是lambda参数类型的子类型。
答案 2 :(得分:0)
使用TypeTag
实施(因为Manifest
已被弃用)
import scala.reflect.runtime.universe._
implicit class AugmentedFunction[T : TypeTag, U](fun: T => U) {
def widen[T1 : TypeTag]: PartialFunction[T1, U] = {
case a if typeOf[T] <:< typeOf[T1] => fun(a.asInstanceOf[T])
}
}