我有一张String
到Function
的地图,详细说明了某种语言的所有有效功能。当我向地图添加一个函数时,我需要指定类型(在本例中为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)
}
相反,我该怎么做:
functionMap += ("Neg" -> expr_neg)
没有[Int]
,稍后在我致电时添加:
(unaryFunctionMap.get("abs").get)[Int](-45)
答案 0 :(得分:5)
您正在尝试使用类型类(在本例中为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)
不需要解析任何类型类隐式调用callFn()
,因为隐含的Numeric
已在调用addFn
时得到解决。
第一个问题是Function1
(或Function2
)不能有隐式参数。只有一种方法可以。 (有关详细说明,请参阅this other question。)因此,如果您想要的内容类似于Function1
但采用隐式参数,则您需要创建自己的类型来定义{{1} } 方法。但它必须是与apply()
不同的类型。
现在我们遇到了主要问题:所有implicits必须能够在编译时解决。在运行方法的代码中的位置,需要选择隐式值所需的所有类型信息。在以下代码示例中:
Function1
我们并不需要指定我们的值类型为unaryFunctionMap("abs")(-45)
,因为它可以从值Int
本身推断出来。但是我们的方法使用-45
隐式值这一事实无法从该行代码中的任何内容推断出来。我们需要在编译时指定Numeric
某处的使用。
如果您可以为带有数值的一元函数设置单独的映射,则(相对)容易:
Numeric
你可以在它需要的类型类上使函数trait泛型,让你的map包含使用不同类型类的一元函数。这需要在内部进行强制转换,并将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)
的规范移动到最终调用函数的位置:
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)
。
此外,这些解决方案都不支持不需要类型类的功能。被强制要明确哪些函数采用隐式参数,以及它们使用什么类型的含义,开始首先打败使用含义的目的。
答案 1 :(得分:3)
你做不到。因为expr_neg
是一个带有类型参数T
的方法,而隐式参数n
取决于该参数。对于Scala将该方法提升为函数,它需要捕获隐式,因此它必须知道您想要的类型。