为什么变量不能在函数文字中分配占位符?

Bru*_*uce 2 scala

我在理解函数文字中的下划线时遇到了麻烦.

val l = List(1,2,3,4,5)
l.filter(_ > 0)
Run Code Online (Sandbox Code Playgroud)

工作良好

l.filter({_ > 0})
Run Code Online (Sandbox Code Playgroud)

工作良好

l.filter({val x=1; 1+_+3 > 0}) // ie you can have multiple statements in your function literal and use the underscore not just in the first statement.
Run Code Online (Sandbox Code Playgroud)

工作良好

但是:

l.filter({val x=_; x > 0})
e>:1: error: unbound placeholder parameter
l.filter({val x=_; x > 0})
Run Code Online (Sandbox Code Playgroud)

我无法将_变量分配给变量,即使以下是合法函数文字:

l.filter(y => {val x=y; x > 0})
Run Code Online (Sandbox Code Playgroud)

工作良好.

是什么赋予了?我的'val x = _'被解释为别的吗?谢谢!

som*_*ytt 8

实际上,你必须备份一步.

你误解了牙箍是如何工作的.

scala> val is = (1 to 5).toList
is: List[Int] = List(1, 2, 3, 4, 5)

scala> is map ({ println("hi") ; 2 * _ })
hi
res2: List[Int] = List(2, 4, 6, 8, 10)
Run Code Online (Sandbox Code Playgroud)

如果println传递给函数的一部分map,你会看到更多的问候.

scala> is map (i => { println("hi") ; 2 * i })
hi
hi
hi
hi
hi
res3: List[Int] = List(2, 4, 6, 8, 10)
Run Code Online (Sandbox Code Playgroud)

你的额外大括号是一个块,这是一些语句后跟一个结果表达式.结果expr是函数.

一旦你意识到只有结果expr具有预期的函数类型map,你就不会想到在前面的语句中使用下划线,因为裸下划线需要预期的类型来确定下划线的含义.

这是类型系统告诉你,你的下划线不在正确的位置.

附录:在评论中你问:

如何使用下划线语法将函数文字的参数绑定到变量

这是一个"愚蠢"的问题,请原谅这个表达方式?

下划线是这样你不必为参数命名,然后你说你想要命名它.

一个用例可能是:传入参数很少,但我只想命名其中一个参数.

scala>(0 /:is)(_ + _)res10:Int = 15

scala>(0 /:is){case(acc,i)=> acc + 2*i} res11:Int = 30

这不起作用,但人们可能想知道为什么.也就是说,我们知道折叠需要什么,我们想用arg来应用.哪个arg?无论在部分应用的部分功能之后剩下什么.

scala>(0 /:is)(({case(_,i)=> _ + 2*i})(_))

要么

scala>(0 /:is)(({case(_,i)=> val d = 2*i; _ + 2*d})(_))

SLS 6.23"匿名函数的占位符语法"提到"expr"边界,当你必须知道下划线代表什么时 - 它本身不是范围.如果您提供下划线的类型归属,它仍会抱怨预期的类型,可能是因为类型推断从左到右.