【问题标题】:Underscores in a Scala map/foreachScala map/foreach 中的下划线
【发布时间】:2018-04-10 22:30:09
【问题描述】:

你能帮我理解下划线在下面第二种情况下的作用吗?我猜它为列表的每个元素定义了一个匿名函数,但为什么不像第一种情况那样调用该函数?

scala> List(1,2,3,4).foreach(x => println("*" * x))
*
**
***
****

scala> List(1,2,3,4).foreach(_ => println("*" * _))
$line25.$read$$iw$$iw$$iw$$iw$$$Lambda$1197/562203102@a632ae0
$line25.$read$$iw$$iw$$iw$$iw$$$Lambda$1197/562203102@a632ae0
$line25.$read$$iw$$iw$$iw$$iw$$$Lambda$1197/562203102@a632ae0
$line25.$read$$iw$$iw$$iw$$iw$$$Lambda$1197/562203102@a632ae0

【问题讨论】:

    标签: scala functional-programming


    【解决方案1】:

    正确的做法如下

    List(1,2,3,4).map("*" * _).foreach(println)
    

    在 scala 中有许多不同的下划线用例。我在这里列出了与这个问题相关的三个用例。

    案例 1:在输入参数中使用下划线

    当输入参数不用于 lambda 表达式的主体时,您可以使用下划线作为 lambda 表达式的参数,因此您可以使用下划线作为占位符,而不是将 lambda 表达式的输入参数声明为如下图所示。 List(1,2,3,4).foreach(_ => println("*" * 10)) // here 10 '*' characters are displayed irrespective of the input value.

    案例 2:在 lambda 表达式主体中使用下划线。

    当在 lambda 表达式的主体中使用下划线时,它指的是输入参数。如果输入仅被引用一次,您可以以这种方式使用下划线。

    例如:List(1,2,3,4).foreach(println("*" * _)) // the underscore will be subsituted with the input argument.

    案例 3:引用未应用的方法。

    假设我有一个方法foo(bar: Int)。我可以通过表达式foo _ 来引用未应用的方法方法(即foo 紧跟一个下划线)。 此处未应用的函数意味着获取对稍后可以按需执行的函数对象的引用。

    @ def foo(bar: Int) = bar
    defined function foo
    @ val baz = foo _
    baz: Int => Int = $sess.cmd24$$$Lambda$2592/612249759@73fbe2ce
    @ baz.apply(10)
    res25: Int = 10
    

    您不能混合使用案例 1 和案例 2。即,您可以在输入参数或 lambda 函数的主体中使用下划线,但不能在两者中使用。由于您混合了这两种情况,因此您意外地使用了下划线用法的情况 3,如下所示。即您指的是通过java.lang.String 上的隐式定义的未应用方法*

    @ "*" * _
    res20: Int => String = $sess.cmd20$$$Lambda$2581/1546372166@20967474
    

    你正在做的事情就像下面这样。

    List(1,2,3,4).foreach(x => println(("*" * _).toString))
    

    【讨论】:

    • 案例 3 在这里实际上并不相关。相反,问题在于您可以混合使用案例 1 和案例 2,可以这么说,它们只是独立应用。
    • 如果你有 "*".* _ 代替,那就是案例 3。虽然奇怪的是,这并不能编译,而 "*".+ _ 可以......
    • yes "*".* _ 是案例 3,我在最后一行答案中显示为 "*" * _
    • 不,如果"*" * _ 成为第 3 种情况,"*" * 必须是一个有效的 SimpleExpr1,它不是(而 "*".* 是)。见scala-lang.org/files/archive/spec/2.12/…
    • 所以我正在做的实际上是针对每个元素(使用下划线作为输入参数,如案例 1),打印对“获取自”函数的引用(不确定术语是否正确) java.lang.String 中的方法 *(案例 3)?谢谢!
    猜你喜欢
    • 2012-01-26
    • 2021-07-04
    • 1970-01-01
    • 2010-12-17
    • 2017-10-17
    • 2015-12-03
    • 1970-01-01
    • 1970-01-01
    • 2015-03-01
    相关资源
    最近更新 更多