2011-01-06 48 views
10

我试图用键定义映射文字:String,值:(Any)=>String。我尝试以下,却得到了一个语法错误:在Scala中定义从字符串到函数的映射

def foo(x: Int): String = /... 
def bar(x: Boolean): String = /... 
val m = Map[String, (Any) => String]("hello" -> foo, "goodbye" -> bar) 
+1

即使你的问题的语法的工作,必须有一些有趣的事情你与类型做派的权利类型,你从地图上获得的功能。这里有更多的复杂性。你真的**想做什么?也许完全有一个更好的解决方案,它不依赖于不同类型函数的映射。 – 2011-01-06 18:05:31

回答

9

有趣的是,没有人实际上给了工作的类型。这里有一个这样的:

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" 
} 
4

如果我让编译器来推断我似乎得到一个非法类型:

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,因为我真的不知道。

3

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>)) 
4

Int =>字符串不是Any =>字符串的子类,相反,相反。当代码期望Any => String时,您不能放置(替换)Int => String函数,因为该代码可以将函数应用于例如“hi”。

@Ben建议的作品,但它有什么用?一旦你从Map中获得它,你就不能调用这个函数。

如果你真的想这样做,也许foo定义为部分功能:

val foo: PartialFunction[Any, String] = {case i: Int => ....} 

显然,这将在运行时,如果你传递一个字符串失败,但你随时可以测试该功能是否适用通过使用isDefinedAt,您可以使用您的参数。 (另一种选择可能是体现,但我没有看到这里的价值)

+0

是的,我即将发布“你如何援引它?”的问题。因为我不认识我自己。 – 2011-01-06 17:35:45

相关问题