为什么这段代码需要一个空行或一个分号? [英] Why does this code need an empty line or a semicolon?

查看:42
本文介绍了为什么这段代码需要一个空行或一个分号?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

case class MyInt(val i : Int) {
    private def factorial(a : Int) : Int = a match {
        case 0 => 1
        case n => (n) * factorial(n-1)
    }
    def ! = factorial(i)
    override def toString = i.toString
}

object MyInt {
    implicit def intToMyInt(x : Int) = MyInt(x)
    implicit def myIntToInt(x : MyInt) = x.i
}
import MyInt._

object Factorial {  
    def main(args: Array[String]): Unit = {
        val a = 5
        val aFact = a!
        println("factorial of " + a + " is " + aFact)

  }
}

如果我没有在 println 之前放分号或空行,它会编译失败:

If I don't put a semicolon or an empty line before println it fails to compile:

递归值 aFact 需要类型

recursive value aFact needs type

推荐答案

所有这些关于递归函数和类型的讨论都是扯淡.Scala 的语法不允许在表达式末尾以外的任何其他地方使用后缀运算符.这就是我们所说的语法:没有任何语义的事物的语法.以下是规范中的相关语法:

All this talk about recursive function and type is a red-herring. Scala's grammar does not allow for postfix operators in any other place than the end of an expression. This is the grammar we are talking about: the syntax of things without any semantics. Here is the relevant grammar from the specs:

Expr        ::= (Bindings | [‘implicit’] id | ‘_’) ‘=>’ Expr
              | Expr1
Expr1       ::= ‘if’ ‘(’ Expr ‘)’ {nl} Expr [[semi] else Expr]
              | ‘while’ ‘(’ Expr ‘)’ {nl} Expr
              | ‘try’ ‘{’ Block ‘}’ [‘catch’ ‘{’ CaseClauses ‘}’]
                [‘finally’ Expr]
              | ‘do’ Expr [semi] ‘while’ ‘(’ Expr ’)’
              | ‘for’ (‘(’ Enumerators ‘)’ | ‘{’ Enumerators ‘}’)
              | {nl} [‘yield’] Expr
              | ‘throw’ Expr
              | ‘return’ [Expr]
              | [SimpleExpr ‘.’] id ‘=’ Expr
              | SimpleExpr1 ArgumentExprs ‘=’ Expr
              | PostfixExpr
              | PostfixExpr Ascription
              | PostfixExpr ‘match’ ‘{’ CaseClauses ‘}’
PostfixExpr ::= InfixExpr [id [nl]]

PostfixExpr 出现在这些旁边的仅有两个地方是 case 语句中的 if 之后和 之前:_* 在参数列表中.所以,看看那个,我们看到后缀表达式的方法名称右侧唯一可以出现的东西是类型描述或match.

The only two places where PostfixExpr appears beside these are after the if on a case statement and before : _* on an argument list. So, looking at that, we see that the only things that can appear on the right side of a postfix expression's method name is a type ascription or a match.

那么,什么结束表达?嗯,表达式出现在语法中的很多地方,所以有很多东西可以结束它.在此特定示例中,表达式是 Block 内的 BlockStat,因此它必须以分号结尾,分号可以推断也可以不推断.

So, what end expressions? Well, expressions appears in a lot of places in the grammar, so there's a lot of things that could end it. In this particular example, the expression is a BlockStat inside a Block, so it must end with a semi-colon, which may be inferred or not.

要推断出这个分号,下一行必须不能被解析为另一种表达式.在这种特殊情况下,我们有:

To infer this semi-colon, it is necessary that the next line must not be something that could be parsed as another kind of expression. In this particular case, we have this:

    val aFact = a!
    println("factorial of " + a + " is " + aFact)

现在,让我们从编译器的角度重写:

Now, let's rewrite that from the point of view of the compiler:

    val id = id id
    id ( stringLit id id id stringLit id id )

这些文字和标识符的解析如下:

These literals and identifiers are parsed like this:

    val id = id id id ( expr )
    val Pattern2 = SimpleExpr1 id SimpleExpr1 ArgumentExprs
    val Pattern2 = InfixExpr
    val Pattern2 = Expr
    val PatDef
    PatVarDef
    Def
    BlockStat

因此,当编译器解析您的程序时,它看起来像是一个有效的中缀表达式.之后,它注意到类型不匹配,但回过头来看看是否可以推断出分号为时已晚.

So that looks like a valid infix expression to the compiler as he parsed your program. Afterwards, it noticed the types didn't match, but it's too late to go back and see if a semi-colon could be inferred.

这篇关于为什么这段代码需要一个空行或一个分号?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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