【问题标题】:Scala syntax: why is anonymous function parameter type parsed differently using parenthesis versus curly braces?Scala 语法:为什么匿名函数参数类型使用括号和花括号进行不同的解析?
【发布时间】:2018-07-11 01:24:31
【问题描述】:

鉴于 Scala 2.12.6:

val list = List(1)
val x = 2

这行得通:

list.map ( y => x + y )

返回List[Int] = List(3)

这很有效:

list.map ( (y: Int) => x + y )

返回相同的值。

同样如此:

list.map { (y: Int) => x + y }

同样的:

list.map { y: Int => x + y }

然而这失败了:

list.map ( y: Int => x + y )

产生错误:

error: not found: type +
list.map ( y: Int => x + y )
                       ^

为什么 Scala 认为 + 是为了表示一种类型,使用括号和花括号之间的区别在哪里记录和解释?

【问题讨论】:

    标签: scala syntax


    【解决方案1】:

    关于匿名函数的Section 6.23 说:

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

    因此,在块 { ... } 中,函数文字 (y: Int) => x + y 可以缩写为 y: Int => x + y

    没有块,整个Int => x + y-part 被视为类型归属,因此错误消息实际上是有意义的。例如,这是一个使违规表达式变为有效的上下文:

    type y = Unit
    type x = Unit
    type +[A, B] = Int
    val y = (i: Int) => 42 + i
    
    val list = List(1)
    
    println(
      list.map ( y: Int => x + y )
    ) // happily prints `List(43)`.
    

    这是因为在两个不同的作用域中有两个ys(一个值,一个类型别名),所以(y: Int => x + y)变成(y: Int => +[x, y]),然后是(y: Int => Int),这只是一个强制执行的类型归属value y 确实是函数类型 Int => Int (它是,所以一切都编译和运行)。 Here 是另一个类似的例子。

    我的建议:坚持使用稍微冗长的(foo: Foo) => { ... } 表示法,它会给尝试阅读和修改代码的每个人带来更少的惊喜。否则会有一些风险

    • 绑定中的参数类型与类型归属冲突
    • 匿名 lambda 的 => 与函数类型 => 冲突
    • 算术运算+ 与二进制中缀类型构造函数+[_,_] 冲突
    • xy 与未定义类型冲突xy

    相同的语法可以同时表示类型和表达式这一事实在某种程度上是一把双刃剑。

    【讨论】:

    • 很好的答案,谢谢。如果它认为我想说y 的类型是Int => x + y。在我的非工作示例中,没有类型 x 那么它是如何通过 x+ 的?
    • @AdamMackler 当编译器试图将Int => x + y解释为一种类型时,它会使用一个看起来有点像=>[Int, +[x, y]]的抽象语法树,=>在顶部,两个孩子@987654354 @ 和 +[x, y],然后在右子节点中,一个节点 + 带有叶 xy。编译器以自上而下的方式扫描 AST,因此它首先遇到+,然后退出并显示错误消息,而没有到达xy。这是因为与值不同,+ 不是在 x 上调用的“方法”(因为类型没有方法),它是二进制类型构造函数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-01
    • 2012-07-17
    • 1970-01-01
    相关资源
    最近更新 更多