代码之家  ›  专栏  ›  技术社区  ›  missingfaktor Kevin Wright

为什么scala的分号推理在这里失败?

  •  16
  • missingfaktor Kevin Wright  · 技术社区  · 15 年前

    在用scala 2.7.3编译以下代码时,

    package spoj
    
    object Prime1 {
      def main(args: Array[String]) {
        def isPrime(n: Int) = (n != 1) && (2 to n/2 forall (n % _ != 0))
        val read = new java.util.Scanner(System.in)
        var nTests = read nextInt // [*]
        while(nTests > 0) {
          val (start, end) = (read nextInt, read nextInt)
          start to end filter(isPrime(_)) foreach println
          println
          nTests -= 1
        }
      }
    }
    

    我得到以下编译时错误:

    PRIME1.scala:8: error: illegal start of simple expression
        while(nTests > 0) {
        ^
    PRIME1.scala:14: error: block must end in result expression, not in definition
      }
      ^
    two errors found
    

    当我在行尾添加分号时,注释为 [*] 程序编译良好。有人能解释一下为什么scala的分号推理不能在那一行上工作吗?

    3 回复  |  直到 14 年前
        1
  •  19
  •   oxbow_lakes    15 年前

    是因为scala假定您使用的是语法吗? a foo b (相当于 a.foo(b) )在你的电话里 readInt . 也就是说,它假定 while 循环是的参数 读数 (记住每个表达式都有一个类型),因此最后一个语句是声明:

    var ntests = read nextInt x
    

    在哪里? x 是你的while block。

    我得说,作为一个优先考虑的问题,我现在已经恢复了使用 a.foo(b)款 语法过度 一个傻瓜 除非专门与设计时考虑了该用途的DSL一起工作 (像演员一样) a ! b )总的来说,它让事情变得更清楚,你不会被这样奇怪的事情咬到!

        2
  •  11
  •   ColinHowe    15 年前

    对Oxbow_Lakes回答的其他评论…

    var ntests = read nextInt()
    

    作为分号的替代方案,应该为您解决问题

        3
  •  8
  •   Matt R    15 年前

    为了增加更多关于分号推理的内容,scala实际上分两个阶段完成了这项工作。首先,它推断出一个特殊的标记 nl 根据语言规范,解析器允许 新加坡国立大学 用作语句分隔符以及分号。然而, 新加坡国立大学 语法也允许在其他一些地方使用。尤其是一个 新加坡国立大学 当下一行的第一个标记可以启动表达式时,允许在中缀运算符之后使用 while 可以启动一个表达式,这就是它以这种方式解释它的原因。不幸的是,尽管 虽然 无法启动表达式,While语句不能用于中缀表达式,因此出现错误。就个人而言,对于解析器来说,这似乎是一种相当奇怪的工作方式,但据我所知,它背后有一个非常合理的理由!

    其他人的另一个建议是,在 [*] 线与 虽然 线路也可以解决问题,因为只有一个 新加坡国立大学 在中缀运算符之后是允许的,因此 新加坡国立大学 S强制解析器进行不同的解释。