我试图用键定义映射文字:String
,值:(Any)=>String
。我尝试以下,却得到了一个语法错误:在Scala中定义从字符串到函数的映射
def foo(x: Int): String = /...
def bar(x: Boolean): String = /...
val m = Map[String, (Any) => String]("hello" -> foo, "goodbye" -> bar)
我试图用键定义映射文字:String
,值:(Any)=>String
。我尝试以下,却得到了一个语法错误:在Scala中定义从字符串到函数的映射
def foo(x: Int): String = /...
def bar(x: Boolean): String = /...
val m = Map[String, (Any) => String]("hello" -> foo, "goodbye" -> bar)
有趣的是,没有人实际上给了将工作的类型。这里有一个这样的:
def foo(x: Int): String = x.toString
def bar(x: Boolean): String = x.toString
val m = Map[String, (Nothing) => String]("hello" -> foo, "goodbye" -> bar)
为什么是这样工作的原因是因为Function1
是输入禁忌变异,所以(Nothing) => String
是(Int) => String
一个超类。它也是输出的共同变体,所以(Nothing) => Any
将是任何其他Function1
的超类。
当然,你不能像那样使用它。没有清单,你甚至不能发现原始类型Function1
是什么。你可以尝试这样的事情,虽然:
def f[T : Manifest](v: T) = v -> manifest[T]
val m = Map[String, ((Nothing) => String, Manifest[_])]("hello" -> f(foo), "goodbye" -> f(bar))
val IntManifest = manifest[Int]
val BooleanManifest = manifest[Boolean]
val StringManifest = manifest[String]
m("hello")._2.typeArguments match {
case List(IntManifest, StringManifest) =>
m("hello")._1.asInstanceOf[(Int) => String](5)
case List(BooleanManifest, StringManifest) =>
m("hello")._1.asInstanceOf[(Boolean) => String](true)
case _ => "Unknown function type"
}
如果我让编译器来推断我似乎得到一个非法类型:
scala> val m = Map("hello" -> foo _, "goodbye" -> bar _)
m: scala.collection.immutable.Map[java.lang.String,(Boolean with Int) => String] =
Map((hello,<function1>), (goodbye,<function1>))
scala> m("hello")(8)
<console>:9: error: type mismatch;
found : Int(8)
required: Boolean with Int
m("hello")(8)
scala> var q = new Boolean with Int
<console>:5: error: illegal inheritance from final class Boolean
var q = new Boolean with Int
不管怎样,你要的是不是那种Any
但通用的“任何类型”,这是_
的:
scala> val mm = Map[String, (_) => String]("hello" -> foo _, "goodbye" -> bar _)
mm: scala.collection.immutable.Map[String,Function1[_, String]] =
Map((hello,<function1>), (goodbye,<function1>))
我刚刚发布了一个问题关于how to invoke such functions,因为我真的不知道。
Trait Function1
是逆变参数,所以def foo(x: Int): String
不是(Any) => String
。因此,以下将工作:
scala> def baz(x: Any): String = "baz"
baz: (x: Any)String
scala> val m2 = Map[String, (String) => String]("hello" -> baz)
m2: scala.collection.immutable.Map[String,(String) => String] = Map((hello,<function1>))
Int =>字符串不是Any =>字符串的子类,相反,相反。当代码期望Any => String时,您不能放置(替换)Int => String函数,因为该代码可以将函数应用于例如“hi”。
@Ben建议的作品,但它有什么用?一旦你从Map中获得它,你就不能调用这个函数。
如果你真的想这样做,也许foo定义为部分功能:
val foo: PartialFunction[Any, String] = {case i: Int => ....}
显然,这将在运行时,如果你传递一个字符串失败,但你随时可以测试该功能是否适用通过使用isDefinedAt,您可以使用您的参数。 (另一种选择可能是体现,但我没有看到这里的价值)
是的,我即将发布“你如何援引它?”的问题。因为我不认识我自己。 – 2011-01-06 17:35:45
即使你的问题的语法的工作,必须有一些有趣的事情你与类型做派的权利类型,你从地图上获得的功能。这里有更多的复杂性。你真的**想做什么?也许完全有一个更好的解决方案,它不依赖于不同类型函数的映射。 – 2011-01-06 18:05:31