【问题标题】:Calling functions saved in a map调用保存在地图中的函数
【发布时间】:2014-09-01 06:30:45
【问题描述】:

我正在阅读Scala School。根据指南,地图可以包含类似的功能

def adder(x: Int, y:Int): Int = x + y
def add2(x:Int):Int = adder(2, x:Int)
val add3 = adder(3, _:Int)

val map = Map(
  "adder" -> { adder(_, _) },
  "add2" -> { add2(_) },
  "add3" -> { add3(_) }
)


好的。上面的代码是编译好的。但是如何调用保存在地图中的函数呢?这些代码不起作用

map.get("adder")(2, 3) // compile error
val adderFunc: (Int, Int) => Int = map.get("adder") // compile error

Scala 编译器给出这个错误信息

[error] /home/user/scalaExample/src/test/scala/CollectionBasicsTest.scala:61: Option[Object] does not take parameters
[error]     map.get("adder")(2, 3) // compile error
[error]                     ^
[error] /home/user/scalaExample/src/test/scala/CollectionBasicsTest.scala:62: type mismatch;
[error]  found   : Option[Object]
[error]  required: (Int, Int) => Int
[error]  val adderFunc: (Int, Int) => Int = map.get("adder") // compile error

【问题讨论】:

    标签: scala collections map


    【解决方案1】:

    这里有两个问题。一个是get 返回一个Option。你可以使用map("adder") 来取回函数。

    第二个也是最基本的问题是你在映射中放置了两个完全不同的东西:一个有两个参数的函数和几个有一个参数的函数。这些类型完全不同,这意味着为映射的值推断的类型是AnyRef。所以,一旦你取回了这样的对象,你就不能对它做任何事情,然后才能让它恢复到一些有用的类型。

    在映射中只保留具有相同数量参数的函数,并使用第一个技巧,一切都会奏效。

    【讨论】:

    • 将具有相同参数的函数放入映射后,我可以调用它们。谢谢。 val map2 = Map( "adder" -> { adder(_, _) } ) assert(map2("adder")(2, 3) == 5)
    【解决方案2】:

    试试:

    map("adder")(2, 3)
    

    .get 返回Option 而不是map 中的值)

    更新

    正如@EndeNeu 指出的那样,scala 的类型推断将映射的类型推断为Map[String, ScalaObject],因为您试图将不同数量的函数放入映射中。

    因此,要使上述示例正常工作,您必须将可泛化为 (Int, Int) => Int 的函数放入您的地图中。

    即具有您示例的功能:

    def adder(x: Int, y:Int): Int = x + y
    def add2(x:Int):Int = adder(2, x:Int)
    val add3 = adder(3, _:Int)
    

    ...你可以拥有这个:

    val map = Map(
      "adder" -> { adder(_, _) },
      "another adder" -> { adder(_, _) }
    )
    
    map("adder")(2, 3)
    

    ...或者这个:

    val map = Map(
      "add2" -> { add2(_) },
      "add3" -> { add3(_) }
    )
    
    map("add2")(2)
    

    ...但是如果您想将所有加法器存储在同一个映射中,则必须将它们概括为通用类型,可以按您期望的方式调用(使用一个或两个参数?)或强制转换它们在运行时使用反射(但这不是类型安全的,对于这种情况似乎不是足够的解决方案),如下所示:

    val map = Map(
      "adder" -> { adder(_, _) },
      "add2" -> { add2(_) },
      "add3" -> { add3(_) }
    )
    
    map("adder").asInstanceOf[(Int, Int) => Int](2, 3)
    

    【讨论】:

    • 地图中的 lambda 将是对象,你不能将它作为方法调用。
    • 嗯。不工作。 assert(map("adder")(2, 3) == 5) [error] /home/user/scalaExample/src/test/scala/CollectionBasicsTest.scala:61: 对象不带参数 [error] assert(map ("adder")(2, 3) == 5) [error] ^ [error] 发现一个错误
    • 没什么区别,那个map的类型是[String, Object],编译器不知道这个对象有两个类型参数,在你的REPL里试试,也调用@987654332 @ 是个坏主意,因为它不安全。
    • 那么,一旦保存 lambda 就不能永远作为函数调用。对吗?
    • 另一方面,如果你只放入 map 函数,然后调用 get("adder").flatMap(adder => adder(1)(2)) 它将起作用。
    猜你喜欢
    • 2020-11-17
    • 2018-04-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-19
    • 2017-12-14
    • 2017-08-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多