2011-02-14 41 views
5

我正在尝试创建一个具有键 - >函数调用映射的类,并且下面的代码不像我希望的那样工作。是否有可能在Scala中有{key - >函数调用}的地图?

class MyClass { 
    val rnd = scala.util.Random 

    def method1():Double = { 
     rnd.nextDouble 
    } 

    def method2():Double = { 
     rnd.nextDouble 
    } 

    def method3():Double = { 
     rnd.nextDouble 
    } 

    def method4():Double = { 
     rnd.nextDouble 
    } 

    def method5():Double = { 
     rnd.nextDouble 
    } 

    var m = Map[String,Double]()  
    m += {"key1"-> method1} 
    m += {"key2"-> method2} 
    m += {"key3"-> method3} 
    m += {"key4"-> method4} 
    m += {"key5"-> method5} 

    def computeValues(keyList:List[String]):Map[String,Double] = { 
     var map = Map[String,Double]() 
     keyList.foreach(factor => { 
      val value = m(factor) 
      map += {factor -> value} 
     }) 
     map 
    } 

} 

object Test { 
    def main(args : Array[String]) { 
     val b = new MyClass 
     for(i<-0 until 3) { 
      val computedValues = b.computeValues(List("key1","key4")) 
      computedValues.foreach(element => println(element._2)) 
     } 
    } 
} 

以下输出

0.022303440910331762 
0.8557634244639081 
0.022303440910331762 
0.8557634244639081 
0.022303440910331762 
0.8557634244639081 

表示一旦该函数被放置在地图,这是一个冷冻实例(每个键产生每一道次的相同的值)。我想看到的行为是,键将引用一个函数调用,产生一个新的随机值,而不是仅仅返回地图中的实例。

+0

为什么有这么多相同的功能呢? – 2011-02-14 17:40:27

+0

@Pablo。它们只是我将实际执行的功能的示例占位符。我希望有一个可以调用的潜在函数的全局,并且只调用它们的一个子集。 – 2011-02-14 17:44:14

回答

16

问题出在你的地图m的签名上。你描述了你想在地图中放置函数;但是您已将其声明为Map[String, Double],这只是字符串的双倍映射。正确的类型将是Map[String,() => Double]

由于括号在no-arg方法调用中是可选的,因此这里的类型差别非常重要。当填充地图时,插入时调用方法以匹配类型签名(我相信这是通过隐式转换完成的,但我不是100%确定的)。

通过简单地改变地图的所声明的签名时,该功能被插入你的愿望,并且可以在computeValues进行评估(需要在35行至map += {factor -> value()}的改变),从而产生以下输出(斯卡拉2.8测试) :

0.662682479130198 
0.5106611727782306 
0.6939805749938253 
0.763581022199048 
0.8785861039613938 
0.9310533868752249 
+0

感谢您的非常明确的解释。我很感激。 – 2011-02-14 17:39:25

+0

这些方法实际上是在插入时调用的,因此它们返回Double,但由于零方法参数可以在没有括号的情况下调用,因此不需要为此目的进行隐式转换。请参阅http://stackoverflow.com/q/6643030/1287856 – 2013-05-24 14:49:56

4

您需要将键映射到函数,而不是函数将给您的答案。试试这个:

var m = Map[String,() => Double]() 
m += /* etc. */ 
m.values.foreach(println(x => x())) 
m.values.foreach(println(x => x())) 
0

我会用scala的类型推断来定义地图。 如果仅通过地图使用方法,则无需分别定义方法。 你也可以使用一个不可变的val,而不是一个可变的var。

val m = Map("key1" -> {() => rnd.nextDouble}, 
    "key2" -> {() => rnd.nextDouble}, 
    "key3" -> {() => rnd.nextDouble}, 
    "key4" -> {() => rnd.nextDouble}, 
    "key5" -> {() => rnd.nextDouble}) 

你也需要改变线35值()

相关问题