您好我正在编写将函数传递给map的任何可能的变体,我最初的理解是它们都会产生相同的结果,但我发现第2,3行实际上产生了不同的输出,第4行是个谜给我
def g(v: Int) = List(v - 1, v, v + 1)
val l = List(1, 2, 3, 4, 5)
// map with some variations
println(l.map { x => g(x) })
println(l.map { (_: Int) => g(_) }) // line 2
println(l.map { (_) => g(_) }) // line 3
println(l.map { _ => }) // line 4
println(l.map { g(_) })
println(l.map { g })
输出:
List(List(0, 1, 2), List(1, 2, 3), List(2, 3, 4), List(3, 4, 5), List(4, 5, 6))
List(<function1>, <function1>, <function1>, <function1>, <function1>)
List(<function1>, <function1>, <function1>, <function1>, <function1>)
List((), (), (), (), ())
List(List(0, 1, 2), List(1, 2, 3), List(2, 3, 4), List(3, 4, 5), List(4, 5, 6))
List(List(0, 1, 2), List(1, 2, 3), List(2, 3, 4), List(3, 4, 5), List(4, 5, 6))
答案 0 :(得分:6)
这些都是将函数g
的应用程序传递给List
的每个元素的等效方法:
l.map { x => g(x) }
l.map { g(_) }
l.map { g }
res17: List[List[Int]] = List(List(0, 1, 2), List(1, 2, 3), List(2, 3, 4), List(3, 4, 5), List(4, 5, 6))
这些是将List
的所有元素映射到g
等未应用函数的等效方法:
l.map { (_: Int) => g(_) }
l.map { (_) => g(_) }
也就是说,映射列表的每个元素实际上都是g
。
scala> l.map { (_: Int) => g(_) }.head
res23: Int => List[Int] = <function1>
scala> res23(0)
res24: List[Int] = List(-1, 0, 1)
实际上,这两者之间的唯一区别是括号和类型注释。它们都相当于:
l.map { _ => g(_) }
以下内容仅将List
的所有元素映射到Unit
:
l.map { _ => }
答案 1 :(得分:3)
让我们从那些返回你期望的结果开始:
println(l.map { x => g(x) })
println(l.map { g(_) })
println(l.map { g })
可以推断这三者都是一回事。实际上,第三个取决于map
期望一个函数的事实,但实际上,它们实际上基本相同。
从最后一个开始,g
是一个命名函数。您使用名称g
对其进行了定义,并使用Int
并返回List[Int]
。
接下来,第一个:x => g(x)
。这是一个匿名函数。它没有名称,它的定义就在那里,在那里写入:它采用参数x
(推断为Int
),并返回List[Int]
(因为这就是调用g(x)
)的作用。
现在,g
和x => g(x)
不是一回事。它们具有相同类型,Int => List[Int]
,但它们是不同的函数,就像我定义def h(x: Int) = g(x)
,h
和g
一样相同的类型,但功能不同。
离开g(_)
。这是x => g(x)
的语法糖。在这种情况下,g(_)
和x => g(x)
实际上是相同的。这是类似_ + _
的特殊情况,这是一个表达式,其中下划线表示函数的参数。有人会认为g(_)
等于g(x => x)
,但这种扩展为x => x
的情况是将函数“移动”到下一个外表达边界的异常。
所以,让我们看看让你怀疑的案例:
println(l.map { (_: Int) => g(_) }) // line 2
首先,我们知道g(_)
与x => g(x)
相同,所以此行等同于
println(l.map { (_: Int) => (x => g(x)) }) // line 2
剩下的下划线与g(_)
中的下划线完全无关。替代参数名称的下划线表示参数名称无关。这与撰写本文基本相同:
println(l.map { (unusedVar: Int) => (x => g(x)) }) // line 2
至于类型,它是Int => (Int => List[Int])
。因此,当您映射列表时,您会得到Int => List[Int]
- 函数的列表! - 打印的是什么。
println(l.map { (_) => g(_) }) // line 3
与第2行相同,只是省略了参数的类型,无论如何都要推断出来。
最后,
println(l.map { _ => }) // line 4
该类型为Int => Unit
。它只需要一个参数,该参数被忽略,不执行任何操作,并返回Unit
(类似于Java中的void
类型)。
Unit
是一种价值无关紧要的东西。函数有来返回一些东西,因为这就是函数所做的事情。当这个问题无关紧要时,我们使用Unit
类型,它只有一个值。 Unit
的唯一值写为()
。
例如,这会返回true
:
def test = {
val a = println("Println returns Unit")
val b: Unit = () // the only possible value
a == b
}
这就是为什么你看到为第4行打印()
的列表:它是List[Unit]
,因此,它的所有元素都是()
。