带有后缀符号的范围上的 toList 导致类型不匹配 [英] toList on Range with suffix notation causes type mismatch

查看:32
本文介绍了带有后缀符号的范围上的 toList 导致类型不匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚开始使用 Scala,并在 Range 和 List 上尝试了一些东西,我通过一个非常简单的片段得到了一些非常奇怪的东西.我使用 sublime 来编辑和执行这些片段:

val a = 1 到 10打印(一)

收益

范围(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

同时

val a = 1 到 10val b = a toList打印(一)

给我错误:

/home/olivier/Dropbox/Projects/ProjectEuler/misc/scala/ch05_ex02.scala:5: 错误:类型不匹配;找到:单位要求:整数打印(一)^发现一个错误

相反,在 REPL 中,我没有收到任何错误.Scala 版本是 2.9.2

解决方案

这是编译器解析后缀表示法(用于元数为 0 的方法).它将尝试将其解析为中缀表示法(如果可能).这会导致编译器像这样解析您的代码:

val a = 1 到 10val b = a toList println(a)

或者特别是后一行用点表示法:

val b = a.toList.apply(println(a))

List[A] 有一个 apply 方法,它采用 A 类型的 varargs(在这种情况下,一个Int) 和 println 返回 Unit.这就是此特定错误消息的原因.

Scala 文档中所述,这种风格不受欢迎:

<块引用>

后缀符号

Scala 允许使用后缀表示法调用 arity-0 的方法:

names.toList//是相同的names toList//不安全,不要使用!

<块引用>

这种风格是不安全的,不应使用.由于分号是可选的,编译器会尝试将其视为中缀方法,可能会从下一行中提取一个术语.

names toListval answer = 42//不会编译!

<块引用>

这最多可能会导致意外的编译错误,最坏的情况是愉快地编译错误代码.尽管某些 DSL 使用了该语法,但应将其视为已弃用并避免使用.

从 Scala 2.10 开始,使用后缀运算符表示法将导致编译器警告.

建议使用点表示法:

val b = a.toList

或者,如果你真的想要,添加一个分号来表示行尾:

val b = a toList;

注意后者会发出编译器警告,如文档中所述:

[warn] 后缀运算符 toList 应该被启用[警告] 通过使隐含值 scala.language.postfixOps 可见.[警告] 这可以通过添加导入子句import scala.language.postfixOps"来实现[警告] 或通过设置编译器选项 -language:postfixOps.[警告] 有关值 scala.language.postfixOps 的讨论,请参阅 Scaladoc[警告] 为什么应该显式启用该功能.[警告] val b = a toList;[警告]^[警告] 发现一个警告

<块引用>

相反,在 REPL 中,我没有收到任何错误.

因为 REPL 是逐行执行的.由于 toList 表达式没有被 println 表达式成功,它会编译.如果您进入粘贴模式 (:paste) 并将其复制为代码块,您将看到相同的行为.

更多信息可以在这个 Scala 用户组问题中找到

I am just starting with Scala, and trying out some things on Range and List, I get something very strange with a very simple snippet. I use sublime to edit and execute these snippets:

val a = 1 to 10
println(a)

yields

Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

while

val a = 1 to 10
val b = a toList
println(a)

gives me the error:

/home/olivier/Dropbox/Projects/ProjectEuler/misc/scala/ch05_ex02.scala:5:     error: type mismatch;
 found   : Unit
 required: Int
println(a)
       ^
one error found

In the REPL, on the contrary, I do not get any error. Scala version is 2.9.2

解决方案

This is caused by the way the compiler parses Suffix Notation (for methods of arity 0). It will try to parse it as Infix Notation (if possible). This causes the compiler to parse your code like this:

val a = 1 to 10
val b = a toList println(a)

Or specifically the latter line with dot notation:

val b = a.toList.apply(println(a))

List[A] has an apply method taking varargs of type A (in this case, an Int) and println returns Unit. That's the reason for this specific error message.

This style is frowned upon as specified in the Scala Documentation:

Suffix Notation

Scala allows methods of arity-0 to be invoked using suffix notation:

names.toList
// is the same as
names toList // Unsafe, don't use!

This style is unsafe, and should not be used. Since semicolons are optional, the compiler will attempt to treat it as an infix method if it can, potentially taking a term from the next line.

names toList
val answer = 42   // will not compile!

This may result in unexpected compile errors at best, and happily compiled faulty code at worst. Although the syntax is used by some DSLs, it should be considered deprecated, and avoided.

As of Scala 2.10, using suffix operator notation will result in a compiler warning.

As recommended, use the dot notation:

val b = a.toList

Or if you really want to, add a semicolon to denote the end of line:

val b = a toList;

Note the latter will emit a compiler warning, as stated in the docs:

[warn] postfix operator toList should be enabled
[warn] by making the implicit value scala.language.postfixOps visible.
[warn] This can be achieved by adding the import clause 'import scala.language.postfixOps'
[warn] or by setting the compiler option -language:postfixOps.
[warn] See the Scaladoc for value scala.language.postfixOps for a discussion
[warn] why the feature should be explicitly enabled.
[warn]   val b = a toList;
[warn]             ^
[warn] one warning found

In the REPL, on the contrary, I do not get any error.

Because the REPL executes on a line by line basis. As the toList expression isn't succeeded by the println expression, it compiles. If you enter paste mode (:paste) and copy it as a block of code, you'll see the same behavior.

More info can be found in this Scala user-group question

这篇关于带有后缀符号的范围上的 toList 导致类型不匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆