Scala 编译器说“错误:需要标识符但找到整数文字。” for () 不是 {}

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17639922/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 05:29:58  来源:igfitidea点击:

Scala compiler says "error: identifier expected but integer literal found." for () not {}

scala

提问by Jacek Laskowski

Why does the Scala 2.11.0-M3compiler give me error: identifier expected but integer literal found.when the round brackets ()are used while it compiles fine with curly brackets {}?

为什么 Scala2.11.0-M3编译器在使用error: identifier expected but integer literal found.圆括号时给我,()而用大括号编译得很好{}

$ scala
Welcome to Scala version 2.11.0-M3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_21).
Type in expressions to have them evaluated.
Type :help for more information.

scala> val s = "this is a string"
s: String = this is a string

scala> s.toList map (c:Char => 1)
<console>:1: error: identifier expected but integer literal found.
       s.toList map (c:Char => 1)
                               ^

scala> s.toList map {c:Char => 1}
res7: List[Int] = List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)

Somehow it compiles fine with the round brackets as well when the left-hand side of the anonymous function is within another pair of the round brackets. Why?

不知何故,当匿名函数的左侧在另一对圆括号内时,它也可以用圆括号很好地编译。为什么?

scala> s.toList map ((c:Char) => 1)
res8: List[Int] = List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)

采纳答案by som-snytt

When you write

当你写

{ i: Int => 2 * i }

{ i: 整数 => 2 * i }

the braces are a block, and the thing inside is the result expression of the block.

大括号是一个块,里面的东西是块的结果表达式。

The syntax is the ResultExpr here. Note that a type is allowed after the param name, as above.

语法是这里的 ResultExpr。请注意,在参数名称之后允许使用类型,如上所示。

That's different from an Exprwhere it is not.

这与Expr不同,它不是。

Here's an example of the difference:

以下是差异的示例:

scala> val is = List(1,2,3)
is: List[Int] = List(1, 2, 3)

The first statement in block has a function literal, an Expr requiring parens if we specify the type. The last statement is the result expression of the block, and no parens are required:

块中的第一条语句有一个函数文字,如果我们指定类型,则需要括号的 Expr。最后一条语句是块的结果表达式,不需要括号:

scala> is map { val f = (i: Int) => 2*i; i: Int => 2*f(i) }
res0: List[Int] = List(4, 8, 12)

Sometimes you don't need to specify the type because it is inferred from the expected type, and with no type in the Expr, you can omit the parens:

有时您不需要指定类型,因为它是从预期类型推断出来的,并且 Expr 中没有类型,您可以省略括号:

scala> is map { val f: Int=>Int = i => 2*i; i: Int => 2*f(i) }

The Bindingsin these productions (in the spec) is your ordinary list of params in parens, which maybe have types. With more than one param, you have to supply parens:

这些作品中的绑定(在规范中)是括号中的普通参数列表,可能有类型。对于多个参数,您必须提供括号:

scala> is reduce { val f = (i:Int,j:Int) => i+j; (i:Int,j:Int) => 2*f(i,j) }
res2: Int = 18

Sometimes you'll see a big block of code as an argument to a function. That's a big function literal as the result expression of a block, which is why you see the parameter sitting out in front, with no parens or braces:

有时您会看到一大段代码作为函数的参数。这是一个大函数文字作为块的结果表达式,这就是为什么您看到参数位于前面,没有括号或大括号:

scala> is map { i =>  val j = 2 * i; /* lots of LOC */ ; j }
res7: List[Int] = List(2, 4, 6)

That is different from the following code, which is block of many lines of code with the function literal at the very end. The function just returns j, or 2:

这与以下代码不同,后者是多行代码块,最后是函数字面量。该函数只返回j,或 2:

scala> is map { val j = 2; /* lots of LOC */ ; _ => j }
res8: List[Int] = List(2, 2, 2)

So we know that you can't write the following:

所以我们知道你不能写以下内容:

scala> is map (is: Int => 2)
<console>:1: error: identifier expected but integer literal found.
       is map (is: Int => 2)
                          ^

What sort of identifier would be meaningful in this context? How about:

在这种情况下,什么样的标识符是有意义的?怎么样:

scala> is map (is: Int => Int)

which yields the delightful result (spoiler alert):

这产生了令人愉快的结果(剧透警报):

java.lang.IndexOutOfBoundsException: 3

This works:

这有效:

scala> val js = List(0,1,2)
js: List[Int] = List(0, 1, 2)

scala> js map (js: Int => Int)
res0: List[Int] = List(0, 1, 2)

The jsin parens is just a value, obviously, not a param, and the type is a type ascription. The value can be a post-fix expression, so this works (or rather, compiles with a feature warning about the post-fix operator syntax):

js中括号只是一个值,显然,不设置了一个param,类型是类型归属。该值可以是后修复表达式,因此这有效(或者更确切地说,编译时带有关于后修复运算符语法的功能警告):

scala> js map (js init: Int => Int)
warning: there were 1 feature warning(s); re-run with -feature for details
java.lang.IndexOutOfBoundsException: 2

More explanation at this answer:

这个答案的更多解释:

https://stackoverflow.com/a/13873899/1296806

https://stackoverflow.com/a/13873899/1296806

There is a category of confusion caused by thinking that parens and curly braces are somehow exchangeable. But I found it clarifying to see braces as BlockExprs, which is what they are. Then it's easier to remember, for instance, that when you use braces in a function application, there is no magic: you've simply supplied a block.

由于认为括号和花括号可以以某种方式交换,因此存在一类混淆。但我发现将大括号视为BlockExprs,这就是它们的含义。然后更容易记住,例如,当您在函数应用程序中使用大括号时,没有什么神奇之处:您只是提供了一个

A block is a bunch of side-effecting statements followed by a result statement. That's obvious for functional programmers, perhaps. But it clarifies that the last thing in your braces is a ResultExpr.

一个块是一堆副作用语句,后跟一个结果语句。这对于函数式程序员来说是显而易见的,也许。但它澄清了大括号中的最后一件事是ResultExpr.

(Footnote: braces for class bodies are different, of course.)

(脚注:当然,类主体的大括号是不同的。)

回答by Arie Xiao

When you write an expression c:Char => 1, Scala compiler treats it as c:(Char => 1), that is, a function variable cwith type Char => 1. However, 1is not a valid type (or type variable), so Scala compiler complains. So you need to write s.toList map ((c:Char) => 1)to help the compiler out of the type association.

当写一个表达式c:Char => 1,Scala编译器把它当作c:(Char => 1),即,函数变量c类型Char => 1。但是,1不是有效的类型(或类型变量),因此 Scala 编译器会抱怨。所以你需要写s.toList map ((c:Char) => 1)来帮助编译器摆脱类型关联。

{c:Char => 1}creates a function literal, that is, a function that accepts a char and returns 1. So

{c:Char => 1}创建一个函数字面量,即一个接受字符并返回 1 的函数。所以

s.toList map {c:Char => 1}

is the same as

是相同的

s.toList map({c:Char => 1})

// or
val fn = {c: Char => 1}
s.toList map fn

However, it seems that Scala doesn't have special specification for the {c:Char => blabla}form for creating function literals.

但是,Scala 似乎没有{c:Char => blabla}对创建函数文字的形式进行特殊规范。

I think it is because that there is {some_var: SomeType => *Class Definition* }form in class definition to reference thiswith some_varand add lower bound of the type of this. This causes the Scala lexer to treat a single typed parameter after {to be formal parameter and treat the statements after =>to be actual body. Note that you CANNOTcreate a function with 2 parameters like this {c: Char, d:Char => 1}.

我想这是因为,有{some_var: SomeType => *Class Definition* }形式类定义的参考thissome_var,并添加下界的类型this。这会导致 Scala 词法分析器将单个类型参数 after{视为形式参数,并将之后的语句=>视为实际主体。请注意,您不能像这样创建带有 2 个参数的函数{c: Char, d:Char => 1}

UPDATE: As commented by som-snytt, it is result expression that causes the brace version to be evaluated to a function result.

更新:正如som-snytt所评论的,结果表达式导致大括号版本被评估为函数结果。

回答by Marcin Pieciukiewicz

I've digged into The Scala Language Specificationfor Scala 2.9, and found out that part 6.23 describes how anonymous function have to be defined:

我深入研究了 Scala 2.9的 Scala 语言规范,发现 6.23 部分描述了如何定义匿名函数:

Expr ::= (Bindings | [‘implicit'] id | ‘_') ‘=>' Expr
ResultExpr ::= (Bindings | ([‘implicit'] id | ‘_') ‘:' CompoundType) ‘=>' Block
Bindings ::= ‘(' Binding {‘,' Binding} ‘)'
Binding ::= (id | ‘_') [‘:' Type]

As you can see Bindingsrequires to be placed inside two surrounding parenthesis. So if your anonymous function defines the type of the parameter, it hasto be defined in this way:

如您所见,Bindings需要放置在两个周围的括号内。因此,如果您的匿名函数定义了参数的类型,则必须以这种方式定义:

(c:Char) => 1

And the call to map should look like that:

对 map 的调用应该是这样的:

s.toList map((c:Char) => 1)

Also in the same part of reference documentation you can find:

同样在参考文档的同一部分,您可以找到:

If an anonymous function (x: T) => e with a single typed parameter appears as the result expression of a block, it can be abbreviated to x: T => e.

如果匿名函数 (x: T) => e 带有单个类型参数作为块的结果表达式出现,则可以缩写为 x: T => e。

So it says that if anonymous function is defied as last expression in a code block, and has exacly one parameter, you can use abbreviated syntax to define anonymous function - without parenthesis. So, in your case, you can write c:Char => 1but only when you place it inside a code block {c:Char => 1}. And you can call map function this way:

所以它说如果匿名函数被定义为代码块中的最后一个表达式,并且只有一个参数,你可以使用缩写语法来定义匿名函数 - 不带括号。所以,在你的情况下,你可以写,c:Char => 1但只有当你把它放在代码块中时{c:Char => 1}。你可以这样调用 map 函数:

s.toList map({c:Char => 1})

or with abbreviated syntax without parenthesis:

或使用不带括号的缩写语法:

s.toList map {c:Char => 1}

On the other hand, when we look back at the anonymous function specification:

另一方面,当我们回顾匿名函数规范时:

Expr ::= (Bindings | [‘implicit'] id | ‘_') ‘=>' Expr

We can see that we can define your anonymous function, if we don't want to specify argument type, without parameter binding in those two ways:

我们可以看到我们可以定义你的匿名函数,如果我们不想指定参数类型,没有参数绑定这两种方式:

s.toList map (c => 1)
// or
s.toList map (_ => 1)


Also, this is summarized in changelog at the end of the documentation (Changes in Version 2.1.7 (19-Jul-2006)):

此外,这在文档末尾的变更日志中进行了总结(2.1.7 版变更(2006 年 7 月 19 日)):

Closure Syntax

闭包语法

The syntax of closures has been slightly restricted (§6.23). The form

闭包的语法略有限制(第 6.23 节)。表格

x: T => E

is valid only when enclosed in braces, i.e. { x: T => E }. The following is illegal, because it might be read as the value x typed with the type T => E:

仅当括在大括号中时才有效,即 { x: T => E }. 以下是非法的,因为它可能被读取为类型为 T => E 的值 x:

val f = x: T => E

Legal alternatives are:

合法的替代方案是:

val f = { x: T => E }
val f = (x: T) => E