【问题标题】:Implicit in Scala 'for' enumerator?Scala'for'枚举器中的隐含?
【发布时间】:2015-04-03 13:08:58
【问题描述】:

如何使for 语句中引入的变量(一个枚举器,在规范中被称为隐式)?

这是我喜欢写的一个例子:

for (implicit genNum: GenNum <- NumGens(200)) {
  val explicitArg = // . . .
  funcWithImplicitGenNum(explicitArg)  // <-- gen passed implicitly here
}

funcWithImplicitGenNum 声明如下:

def funcWithImplicitGenNum(explicitArg: Whatever)(implicit gen: GenNum) = ???

如果我正确理解规范,它不允许 for 的枚举器是隐式的,所以我必须这样做:

for (g <- NumGens(200)) {
  implicit val genNum: GenNum = g
  val explicitArg = // . . .
  funcWithImplicitGenNum(explicitArg)  // <-- gen passed implicitly here
}

这种解决方法不是世界末日,但它困扰着我。在我的实际程序中,我在各处隐式传递了几个变量,它们提供了发生某事的整体上下文。 Scala 的隐式在这方面非常出色:它们极大地减少了代码中的混乱程度,而调用堆栈深处的函数可以访问该上下文信息。唯一的例外是for 循环:我必须使用这种笨拙的技巧来定义等于枚举变量的val

有没有办法隐式传递genNum?或者,如果不是,您是否知道我应该为 for 语句不允许将其 Enumerator 设为隐式感到高兴的原因? (通常,如果您知道语言功能的基本原理,您会更好地了解如何“顺其自然”。)


这里有一点背景,如果有帮助的话。我正在编写一个使用各种变异算子的遗传算法。变异算子不应该知道它被调用的是哪一代。但我也在收集有关突变在不同世代中表现的数据。数据收集代码确实需要知道它是哪一代,以及其他一些东西。因此,我显式传递了与突变相关的变量,隐式传递了数据收集所需的变量。

【问题讨论】:

    标签: scala implicit


    【解决方案1】:

    目前这是不可能的。 Here 是相关功能请求的票证。 Martin Odersky 在那里写道:

    我看到的问题是与许多其他事物的交互。 [隐式变量] 可能是一种模式——隐含应该适用于它的所有 变量?那么,生成器在 for 表达式中的翻译是 相当参与。我们必须指定如何考虑隐式 帐户。

    作为一种解决方法,您可以将implicit 循环放在包装mapflatMap 中(当然,这并不理想):

    class Foo
    
    object FooRunner {
        val foos = List(new Foo, new Foo, new Foo)
        def runFoo(i: Int)(implicit foo: Foo) = println(s"Foo ran $i")
    
        def runFoos = foos.map { implicit foo =>
            for(i <- (1 to 100)) {
                runFoo(i) //implicit works here.
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      您可以像这样显式传递隐式参数:

      for (val genNum <- NumGens(200)) {
        val explicitArg = // . . .
        funcWithImplicitGenNum(explicitArg)(genNum)  // <-- gen passed explictly here
      }
      

      至于为什么的问题,我没有证据,但考虑到范围影响,这将表明您在一段隐式 for 循环中使用了 val i,而另一个文件中的另一个程序员正在尝试做一个简单的 for 循环带有变量名。 巫毒将随之而来

      虽然我实际上会映射(或 foreach 取决于功能副作用)

      val result = NumGens(200).map{ implicit i =>
      val explicitArg = ??
      funcWithImplicitGenNum(explicitArg)
      }
      

      【讨论】:

      • 明确地传递变量肯定是后备位置。不过,我希望避免它,因为这样我就必须在循环中通过隐式传递的任何地方添加它(在我的实际程序中,有几个隐式)。基本上,这将放弃隐含——不是世界末日,而是令人失望。
      • 嗯,调用.map.foreach 可能就是解决方案。如果我理解正确,你的例子可以去.map { implicit genNum i =&gt; ... }。对吗?
      • 关于范围,我想我已经控制住了,因为每个隐式 val 的类型确保它在需要的地方准确传递,而不管 val 的名称如何。事实上,就我的目的而言,val doesn't even need a name,因为它的类型说明了我和编译器都需要知道的一切。为变量命名只会产生不希望出现的阴影。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-23
      • 1970-01-01
      • 2011-03-22
      • 2015-08-08
      • 2010-11-26
      • 1970-01-01
      相关资源
      最近更新 更多