带有下划线的scala传递函数产生一个函数而不是一个值
scala passing function with underscore produces a function not a value
您好,我正在编写将函数传递给映射的任何可能变体,我最初的理解是它们都会产生相同的结果,但我发现第 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))
这些都是将函数 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 { _ => }
让我们从那些return您期望的结果开始:
println(l.map { x => g(x) })
println(l.map { g(_) })
println(l.map { g })
可以推断这三者是一回事。实际上,第三个取决于map
期望一个功能,但说实话,它们确实基本相同。
从最后一个开始,g
是一个命名函数。您使用名称 g
定义了它,采用 Int
和 returning List[Int]
.
接下来,第一个:x => g(x)
。这是一个 匿名 函数。它没有名字,它的定义就在那里,它写的地方:它有一个参数 x
(被推断为 Int
),并且 return 是一个 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
,是一个例外,"moves" 函数指向下一个外部表达式边界.
那么,让我们看看让你疑惑的案例:
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
。它只是接受一个参数,该参数被忽略,不执行任何操作,并且 return 是一个 Unit
(类似于 Java 中的 void
类型)。
Unit
是一种表示值无关紧要的事物的类型。一个函数 有 到 return 的东西,因为这就是函数的作用。当那件事无关紧要时,我们使用 Unit
类型,它只有一个值。 Unit
的唯一值写为 ()
.
例如,这个 returns true
:
def test = {
val a = println("Println returns Unit")
val b: Unit = () // the only possible value
a == b
}
这就是为什么您会看到第 4 行打印了一个 ()
列表:它是一个 List[Unit]
,因此,它的所有元素都是 ()
.
您好,我正在编写将函数传递给映射的任何可能变体,我最初的理解是它们都会产生相同的结果,但我发现第 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))
这些都是将函数 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 { _ => }
让我们从那些return您期望的结果开始:
println(l.map { x => g(x) })
println(l.map { g(_) })
println(l.map { g })
可以推断这三者是一回事。实际上,第三个取决于map
期望一个功能,但说实话,它们确实基本相同。
从最后一个开始,g
是一个命名函数。您使用名称 g
定义了它,采用 Int
和 returning List[Int]
.
接下来,第一个:x => g(x)
。这是一个 匿名 函数。它没有名字,它的定义就在那里,它写的地方:它有一个参数 x
(被推断为 Int
),并且 return 是一个 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
,是一个例外,"moves" 函数指向下一个外部表达式边界.
那么,让我们看看让你疑惑的案例:
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
。它只是接受一个参数,该参数被忽略,不执行任何操作,并且 return 是一个 Unit
(类似于 Java 中的 void
类型)。
Unit
是一种表示值无关紧要的事物的类型。一个函数 有 到 return 的东西,因为这就是函数的作用。当那件事无关紧要时,我们使用 Unit
类型,它只有一个值。 Unit
的唯一值写为 ()
.
例如,这个 returns true
:
def test = {
val a = println("Println returns Unit")
val b: Unit = () // the only possible value
a == b
}
这就是为什么您会看到第 4 行打印了一个 ()
列表:它是一个 List[Unit]
,因此,它的所有元素都是 ()
.