考虑一个通用函数:
def genericFn[T](fn: T => Boolean): Unit = {
// do something involves T
}
是否可以限制T
(在编译时)是一个简单类型,而不是类似的类型List[Int]
?
我想解决的底层问题是这样的:
var actorReceive: Receive = PartialFunction.empty
def addCase[T](handler: T => Boolean): Unit = {
actorReceive = actorReceive orElse ({
case msg: T => // call handle at some point, plus some other logic
handler(msg)
})
}
the addCase
函数会导致类型擦除警告,这可以通过要求来解决ClassTag
like: def addCase[T: ClassTag](...
, but ClassTag
仍然无法防范这样的电话:
addCase[List[Int]](_ => {println("Int"); true})
addCase[List[String]](_ => {println("String"); false})
actorReceive(List("str")) // will print "Int"
上面的代码将打印"Int"
虽然根本没有发出任何警告或错误,但有什么办法吗?
如果没有反射,就无法在类型系统中按原样强制执行此操作。
最好的方法是拥有一个类型类,例如NonEraseable[A]
,这提供了类型没有会在运行时被删除的类型参数的证据。隐含的NonEraseable[A]
在范围内应该意味着A
没有类型参数。由于手动创建这些内容会很乏味,因此隐式宏可以完成这项工作:
import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
trait NonEraseable[A]
object NonEraseable {
implicit def ev[A]: NonEraseable[A] = macro evImpl[A]
def evImpl[A](c: Context)(implicit tt: c.WeakTypeTag[A]): c.Expr[NonEraseable[A]] = {
import c.universe._
val tpe = weakTypeOf[A]
if(tpe.dealias.typeArgs.isEmpty)
c.Expr[NonEraseable[A]](q"new NonEraseable[$tpe] {}")
else
c.abort(c.enclosingPosition, s"$tpe contains parameters that will be erased at runtime.")
}
}
使用案例:
def onlySimple[A : NonEraseable](value: A): Unit = println(value)
scala> onlySimple(1)
1
scala> onlySimple(List(1, 2, 3))
<console>:13: error: List[Int] contains parameters that will be erased at runtime.
onlySimple(List(1, 2, 3))
^
使用这个,你可以强制执行在编译时一个类型参数A
与上下文绑定NonEraseable
是您想要的类型。 (假设您没有作弊并手动创建类型类的实例)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)