可以给个{key->;的地图吗? Scala 中的函数调用}?

发布于 2024-10-17 03:27:50 字数 1383 浏览 3 评论 0原文

我正在尝试创建一个具有键映射的类 ->函数调用,并且以下代码的行为不符合我的预期。

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

表明,一旦将函数放置在映射中,它就是一个冻结实例(每个键为每次传递生成相同的值)。我希望看到的行为是键引用函数调用,生成新的随机值,而不是仅返回映射中保存的实例。

I'm trying to create a class that has a map of keys -> function calls, and the following code is not behaving as I would like it to.

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

The following output

0.022303440910331762
0.8557634244639081
0.022303440910331762
0.8557634244639081
0.022303440910331762
0.8557634244639081

indicates that once the function is placed in the map, it's a frozen instance (each key producing the same value for each pass). The behavior I would like to see is that the key would refer to a function call, generating a new random value rather than just returning the instance held in the map.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

千纸鹤带着心事 2024-10-24 03:27:50

问题出在您的地图 m 的签名上。您描述了您想要将功能放入地图中;但是您已将其声明为 Map[String, Double] ,它只是字符串到双精度数的映射。正确的类型是 Map[String, () =>双]。

由于括号在无参数方法调用中是可选的,因此这里类型的差异非常重要。填充映射时,会在插入时调用这些方法以匹配类型签名(我相信这是通过隐式转换完成的,但我不能 100% 确定)。

只需更改映射的声明签名,即可根据需要插入函数,并且可以在computeValues期间进行评估(需要将第35行更改为map += {factor -> value()}),产生以下输出(在 Scala 2.8 上测试):

0.662682479130198
0.5106611727782306
0.6939805749938253
0.763581022199048
0.8785861039613938
0.9310533868752249

The problem is with the signature of your map m. You described that you wanted to put functions in the map; however you've declared it as Map[String, Double] which is just a map of strings to doubles. The correct type would be Map[String, () => Double].

Because brackets are optional on no-arg method invocations, the difference in types here is very important. When the map is being populated, the methods are invoked at insertion time in order to match the type signature (I believe this is done by an implicit conversion but I'm not 100% sure).

By simply changing the declared signature of your map, the functions are inserted as you desire, and can be evaluated during computeValues (requires a change on line 35 to map += {factor -> value()}), resulting in the following output (tested on Scala 2.8):

0.662682479130198
0.5106611727782306
0.6939805749938253
0.763581022199048
0.8785861039613938
0.9310533868752249
巾帼英雄 2024-10-24 03:27:50

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

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

You need to map the keys to functions, not to the answer that the function would give you. Try this:

var m = Map[String,() => Double]()
m += /* etc. */
m.values.foreach(println(x => x()))
m.values.foreach(println(x => x()))
断爱 2024-10-24 03:27:50

我会使用 scala 的类型推断来定义映射。
如果仅通过地图使用这些方法,则无需单独定义这些方法。
您还可以使用不可变的 val,而不是可变的 var。

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

您还需要将第 35 行更改为 value()

I would use scala's type inference to define the map.
There's no need to define the methods separately, if they're only used via the map.
Also you can use an immutable val, instead of a mutable var.

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

You also need to change line 35 to value()

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文