在 Scala 中,使用“_”和使用命名标识符有什么区别?
当我尝试使用 _
而不是使用命名标识符时,为什么会出现错误?
scala> res0
res25: List[Int] = List(1, 2, 3, 4, 5)
scala> res0.map(_=>"item "+_.toString)
<console>:6: error: missing parameter type for expanded function ((x$2) => "item
".$plus(x$2.toString))
res0.map(_=>"item "+_.toString)
^
scala> res0.map(i=>"item "+i.toString)
res29: List[java.lang.String] = List(item 1, item 2, item 3, item 4, item 5)
Why do i get an error when I try using _
instead of using a named identifier?
scala> res0
res25: List[Int] = List(1, 2, 3, 4, 5)
scala> res0.map(_=>"item "+_.toString)
<console>:6: error: missing parameter type for expanded function ((x$2) => "item
".$plus(x$2.toString))
res0.map(_=>"item "+_.toString)
^
scala> res0.map(i=>"item "+i.toString)
res29: List[java.lang.String] = List(item 1, item 2, item 3, item 4, item 5)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
像这样用来代替变量名的下划线是特殊的;第 N 个下划线表示匿名函数的第 N 个参数。因此,以下内容是等效的:
但是,如果您这样做:
那么您将使用一个忽略其单个参数并返回由
_ + 1
定义的函数的函数来映射列表。 (这个特定的示例将无法编译,因为编译器无法推断第二个下划线的类型。)具有命名参数的等效示例如下所示:简而言之,在函数的参数列表中使用下划线意味着“我忽略这些参数”在此函数的主体中。”在正文中使用它们意味着“编译器,请为我生成一个参数列表”。这两种用法不能很好地混合。
Underscores used in place of variable names like that are special; the Nth underscore means the Nth argument to an anonymous function. So the following are equivalent:
But, if you do this:
Then you are mapping the list with a function that ignores its single argument and returns the function defined by
_ + 1
. (This specific example won't compile because the compiler can't infer what type the second underscore has.) An equivalent example with named parameters would look like:In short, using underscores in a function's argument list means "I am ignoring these arguments in the body of this function." Using them in the body means "Compiler, please generate an argument list for me." The two usages don't mix very well.
为了补充其他答案,这里有一些示例,说明为什么在某些情况下使用“_”作为占位符参数时会出现“缺少参数类型”。
Scala 的类型推断根据表达式的上下文来考虑表达式的“预期”类型。如果没有上下文,则无法推断参数的类型。请注意,在错误消息中,
_
的第一个和第二个实例被编译器生成的标识符x$1
和x$2
替换。向整个表达式添加类型归属可以提供足够的上下文来帮助推断器:
或者,您可以向每个参数占位符添加类型归属:
在下面提供类型参数的函数调用中,上下文是明确的,并且可以推断函数类型。
但是,如果我们要求编译器推断类型参数,如果失败:
我们可以通过柯里化参数列表来帮助它。这里,第一个参数列表
(1, 1)
的参数告诉推断类型参数A
应该是Int
。然后它知道参数f
的类型必须是(Int, Int) => ?)
,返回类型R
被推断为Int
,即整数加法的结果。您将在标准库的Traversable.flatMap
中看到相同的方法。To complement the other answers, here are some examples showing why you get the "missing parameter type" in some cases when using '_' as a placeholder parameter.
Scala's type inference considers the 'expected' type of an expression based on its context. If there is no context, it cannot infer the type of the parameters. Notice in the error message the first and second instances of
_
are replaced with the compiler generated identifiersx$1
andx$2
.Adding a type ascription to the entire expression provides enough context to help the inferencer:
Alternatively, you can add a type ascription to each parameter placeholder:
In the function call below with type arguments provided, the context is unambigous and the function type is inferred.
However, if we ask the compiler to infer the type parameters, if fails:
We can help it, though, by currying the parameter lists. Here, the arguments to the first parameter list
(1, 1)
, tell the inference that the type parameterA
should beInt
. It then knows that the type of the argumentf
must be(Int, Int) => ?)
, and the return typeR
is inferred asInt
, the result of integer addition. You will see the same approach used inTraversable.flatMap
in the standard library.如果您不打算绑定标识符,请忽略该部分。
If you're not going to bind an identifier, just leave that part out.