Scala-泛型类型函数的映射
如何创建字符串到具有泛型类型的函数的映射?例如,我希望能够在编译时创建映射:Scala-泛型类型函数的映射,scala,Scala,如何创建字符串到具有泛型类型的函数的映射?例如,我希望能够在编译时创建映射: var unaryFunctionMap: Map[String, Any => Any] = Map[String, Any => Any]() 然后,我想添加一些函数,这些函数可以接受String、Int、Double等类型的组合。可能的方式如下: unaryFunctionMap += ("Abs" -> Functions.add) unaryFunctionMap += ("Neg" -&
var unaryFunctionMap: Map[String, Any => Any] = Map[String, Any => Any]()
然后,我想添加一些函数,这些函数可以接受String
、Int
、Double
等类型的组合。可能的方式如下:
unaryFunctionMap += ("Abs" -> Functions.add)
unaryFunctionMap += ("Neg" -> Functions.neg)
unaryFunctionMap += ("Rev" -> Functions.rev)
其中,我在我的函数
类中实现了实际函数:
def abs[T: Numeric](value: T)(implicit n: Numeric[T]): T = {
n.abs(value)
}
def neg[T: Numeric](value: T)(implicit n: Numeric[T]): T = {
n.negate(value)
}
def rev(string: String): String = {
string.reverse
}
因此,abs
和neg
都允许Numeric
类型,而rev
只允许字符串
s。当我使用映射时,我希望能够在必要时指定键入。大概是这样的:
(unaryFunctionMap.get("abs").get)[Int](-45)
或者,如果这不可能
(unaryFunctionMap.get("abs").get)(Int, -45)
如何修改代码以实现此功能?听起来您需要的是类型类。具体来说,对于数字,您实际上不需要定制的TypeClass,因为Scala已经提供了它们。如果您不想在所有类型之间共享行为,您只需扩展
object Test {
// In this case you can probably even specialize to avoid unboxing.
implicit class NumericOps[T : Numeric](val obj: T) extends AnyVal {
def whatever(x: T): T = obj.add(x) // for instance
}
}
然后,对于所有数字,您可以免费获得增强:
import Test._
5.whatever(6)// = 11
只要对字符串重复相同的模式,这是一个正常的pimp-my-library模式。如果您想在一堆不相关的类型上实现相同的操作,请查看类型类。将函数存储为
Any=>Any
的问题是,函数的参数类型是逆变的,但返回类型是协变的,因此Int=>Int
不是Any=>Any
的子类型。您可以使用存在类型来解决这个问题,但这仍然不能提供类型安全性
作为一种解决方案,您可能希望使用Map[Type,Map[String,=>\u]]]
并确保放入Map的每个条目都只使用相应类型的函数
以下是一个草图,而不是一个确定的解决方案;我对类型标记的了解不足以保证性能的正确性或合理性(这需要反射才能工作)
由于方法get
中的显式强制转换,这可能是不安全的,因此我们需要确保internal
的填充正确
用法示例:
object UnaryFunctionMap {
def main(args: Array[String]) {
val neg: Int => Int = i => -i
val rev: String => String = s => s.reverse
val map = new UnaryFunctionMap
map += ("neg", neg)
map += ("rev", rev)
println(map.get[Int]("neg").map(_.apply(-45))) // Some(45)
println(map.get[String]("neg").map(_.apply("reverto"))) // None
println(map.get[Int]("rev").map(_.apply(-45))) // None
println(map.get[String]("rev").map(_.apply("reverto"))) // Some(otrever)
}
}
注意,对于任意类型的
A
,我假设函数为A=>A
。如果您希望任意A
和B
的函数为A=>B
,则需要将第二种类型添加到映射中,并相应地更新这两种方法 你想用这个干什么?这种类型的Any=>Any
映射通常是Scala中要避免的反模式。了解您的用例可能有助于回答者确定一个更好的设计模式,以便在这里使用。我想创建一个函数名到函数的映射。这些函数可以是String=>String
,Int=>String
,Double=>Double
,等等,所以我使用了Any=>
。这些函数通常也是T:Numeric=>T
,因此我希望能够在运行时传递T
是什么类型的。这一点很清楚。我试图更好地理解您想要使用此映射的目的。我使用解析器将用户表达式解析为函数和操作数。地图包含了语言中的所有有效函数。我不确定这是否是一个更好的问题,但这更具体地说是我目前试图实现的:我不确定我是否理解你的建议。我如何在我的函数映射中实现这一点?我是否需要这样做:``functionMap+=(“Neg”->(value=>value.abs())?当我尝试此操作时,会出现编译错误,因为
abs``不是Any
的成员。
object UnaryFunctionMap {
def main(args: Array[String]) {
val neg: Int => Int = i => -i
val rev: String => String = s => s.reverse
val map = new UnaryFunctionMap
map += ("neg", neg)
map += ("rev", rev)
println(map.get[Int]("neg").map(_.apply(-45))) // Some(45)
println(map.get[String]("neg").map(_.apply("reverto"))) // None
println(map.get[Int]("rev").map(_.apply(-45))) // None
println(map.get[String]("rev").map(_.apply("reverto"))) // Some(otrever)
}
}