【问题标题】:Referencing instance member from anonymous function从匿名函数引用实例成员
【发布时间】:2014-06-26 08:25:19
【问题描述】:

我正在尝试定义一个类,其实例具有String 和一个函数。在函数中使用了String 参数。

class Tenant(val name: String, exclusion: Map[String, Int] => Boolean)

val rule1 = new Tenant(name = "Baker3",
  (suggestedFloor: Map[String, Int]) => suggestedFloor(name) != topFloor)

val rule1 = new Tenant(name = "Cooper2",
  (suggestedFloor: Map[String, Int]) => suggestedFloor(name) != groundFloor)

最后一次使用名称时出错:not found: value name

我该怎么做?

【问题讨论】:

  • 更正:name 的两种使用都会产生not found: value name,而不仅仅是最后一种。

标签: scala scoping lexical-scope


【解决方案1】:

问题:

您正试图在根本不可用的词汇上下文中引用名称 name

val rule1 = new Tenant(name = "Cooper2",
  (suggestedFloor: Map[String, Int]) => suggestedFloor(name) != groundFloor)

——name 在这个上下文中不是指在Tenant 中定义的name,而是指在rule1 定义范围内的名称name,当然它显然不是存在。使用此代码,错误会消失,但这当然不是您想要的:

val name = ??? // this is the `name` that gets referenced by the lambda

val rule1 = new Tenant(name = "Cooper2",
  (suggestedFloor: Map[String, Int]) => suggestedFloor(name) != groundFloor)

解决方案:

要解决这个问题,不要在实例化时传入函数,而是使用方法覆盖:

abstract class Tenant(val name: String) {
  def exclusion(suggestedFloor: Map[String, Int]): Boolean
}

val rule1 = new Tenant(name = "Baker3") {
  def exclusion(suggestedFloor: Map[String, Int]) =
    suggestedFloor(name) != topFloor
}

这将创建Tenant 的匿名子类,并为exclusion 定义“自定义”;我想说,这在 Scala 中也被视为惯用风格。

或者,您可以使用稍微不同的语义,而不是覆盖方法,而是覆盖包含函数的属性;当与使用 _ 的更紧凑形式的 lambda 定义结合使用时,这将产生更短的语法:

abstract class Tenant(val name: String) {
  val exclusion: Map[String, Int] => Boolean
}

val rule1 = new Tenant(name = "Baker3") {
  val exclusion = (_: Map[String, Int])(name) != topFloor
}

不幸的是,类型推断器并没有消除对 Map[String, Int] 重新声明的需要,原因只有比我聪明的人才能详细说明。

【讨论】:

    【解决方案2】:

    你需要柯里化你的函数或类声明:

    class Tenant(name: String)(exclusion: Map[String, Int] => Boolean = _(name) != topFloor)
    

    现在创建一个实例:

    scala> new Tenant("hello")()
    res8: Tenant = Tenant@13c3c24f
    

    【讨论】:

    • 感谢您的快速响应,但每个实例都有另一个谓词。它与实际的函数文字有关。
    • @Epicurist 我不确定我是否了解您的需求。您可以在声明或实例化站点传递任何函数。如果你想在你的谓词中使用你的 name 参数,那么你需要 curry 你的类声明
    • @Epicurist 我明白了,但是不,您不能那样引用参数字段。但是您可以在第一个 arg 列表中传递上限,并在第二个列表中的默认函数中使用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-17
    • 2010-11-09
    • 1970-01-01
    • 2015-06-28
    • 2011-03-03
    • 1970-01-01
    相关资源
    最近更新 更多