Cor*_* Wu 1 generics scala implicit typeclass
我有地图的String,以FunctionS的所有细节的是在语言的有效功能.当我向地图添加一个函数时,我需要指定类型(在本例中Int).
var functionMap: Map[String, (Nothing) => Any] = Map[String, (Nothing) => Any]()
functionMap += ("Neg" -> expr_neg[Int])
def expr_neg[T: Numeric](value: T)(implicit n: Numeric[T]): T = {
n.negate(value)
}
Run Code Online (Sandbox Code Playgroud)
相反,我该怎么做:
functionMap += ("Neg" -> expr_neg)
Run Code Online (Sandbox Code Playgroud)
没有,[Int]并在我打电话后添加它:
(unaryFunctionMap.get("abs").get)[Int](-45)
Run Code Online (Sandbox Code Playgroud)
您正在尝试使用类型类(在本例中Numeric)构建函数.类型类依赖于隐式参数.隐含在编译时解决.您的函数名称字符串值仅在运行时已知,因此您不应在类似类之上构建解决方案.
另一种方法是在地图中为每个参数类型存储单独的函数对象.您可以使用以下内容存储参数类型TypeTag:
import scala.reflect.runtime.universe._
var functionMap: Map[(String, TypeTag[_]), (Nothing) => Any] = Map()
def addFn[T: TypeTag](name: String, f: T => Any) =
functionMap += ((name, typeTag[T]) -> f)
def callFn[T: TypeTag](name: String, value: T): Any =
functionMap((name, typeTag[T])).asInstanceOf[T => Any](value)
addFn[Int]("Neg", expr_neg)
addFn[Long]("Neg", expr_neg)
addFn[Double]("Neg", expr_neg)
val neg10 = callFn("Neg", 10)
Run Code Online (Sandbox Code Playgroud)
没有类型类隐式需要解析才能调用callFn(),因为隐式Numeric调用已经解析了addFn.
第一个问题是a Function1(或Function2)不能有隐式参数.只有一种方法可以.(有关更多解释,请参阅此其他问题.)因此,如果您想要一些行为类似Function1但采用隐式参数的东西,则需要创建自己的类型来定义apply()方法.但它必须是一种不同的类型Function1.
现在我们解决了主要问题:所有implicits都必须能够在编译时解决.在运行方法的代码中的位置,需要选择隐式值所需的所有类型信息.在以下代码示例中:
unaryFunctionMap("abs")(-45)
Run Code Online (Sandbox Code Playgroud)
我们并不需要指定我们的值类型Int,因为它可以从值-45本身推断出来.但是我们的方法使用Numeric隐式值的事实无法从该行代码中的任何内容推断出来.我们需要Numeric在编译时指定某处的使用.
如果您可以为带有数值的一元函数创建单独的映射,则(相对)容易:
trait UnaryNumericFn {
def apply[T](value: T)(implicit n: Numeric[T]): Any
}
var unaryNumericFnMap: Map[String, UnaryNumericFn] = Map()
object expr_neg extends UnaryNumericFn {
override def apply[T](value: T)(implicit n: Numeric[T]): T = n.negate(value)
}
unaryNumericFnMap += ("Neg" -> expr_neg)
val neg3 = unaryNumericFnMap("Neg")(3)
Run Code Online (Sandbox Code Playgroud)
你可以在它需要的类型类上使函数trait泛型,让你的map包含使用不同类型类的一元函数.这需要在内部进行强制转换,并将规范移动Numeric到最终调用函数的位置:
trait UnaryFn[-E[X]] {
def apply[T](value: T)(implicit ev: E[T]): Any
}
object expr_neg extends UnaryFn[Numeric] {
override def apply[T](value: T)(implicit n: Numeric[T]): T = n.negate(value)
}
var privateMap: Map[String, UnaryFn[Nothing]] = Map()
def putUnary[E[X]](key: String, value: UnaryFn[E]): Unit =
privateMap += (key -> value)
def getUnary[E[X]](key: String): UnaryFn[E] =
privateMap(key).asInstanceOf[UnaryFn[E]]
putUnary("Neg", expr_neg)
val pos5 = getUnary[Numeric]("Neg")(-5)
Run Code Online (Sandbox Code Playgroud)
但你还是要指定Numeric某个地方.
此外,这些方法都无法解决,因为写的,支持函数的并不需要类型类.被强制要明确哪些函数采用隐式参数,以及它们使用什么类型的含义,首先就会破坏使用含义的目的.
| 归档时间: |
|
| 查看次数: |
413 次 |
| 最近记录: |