为什么这段代码需要空行或分号?

时间:2010-09-17 12:35:04

标签: scala

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之前没有添加分号或空行,则无法编译:

  

递归值aFact需要类型

3 个答案:

答案 0 :(得分:10)

所有关于递归函数和类型的讨论都是红鲱鱼。 Scala的语法不允许在表达式结尾之外的任何其他位置使用后缀运算符。这是我们正在谈论的语法:没有任何语义的事物的语法。以下是规范中的相关语法:

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旁边出现if的唯一两个地方是case语句: _*之后和参数列表match之前的BlockStat。因此,看一下,我们看到在后缀表达式的方法名称右侧可以出现的唯一内容是类型归属或Block

那么,什么结束表达?好吧,表达式出现在语法的很多地方,所以有很多东西可以结束它。在此特定示例中,表达式是 val aFact = a! println("factorial of " + a + " is " + aFact) 内的 val id = id id id ( stringLit id id id stringLit id id ) ,因此它必须以分号结尾,这可能是推断的。

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

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

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

{{1}}

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

{{1}}

因此,在解析程序时,它看起来像编译器的有效中缀表达式。之后,它注意到类型不匹配,但现在回去看看是否可以推断出分号是太晚了。

答案 1 :(得分:6)

因为否则!可以被解释为二进制表达式

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

如果编译器推翻了所涉及的两种类型的表达式,则可以证明相反的情况,因为有可能对允许调用的这些类型进行隐式转换。

但由于右操作数本身涉及aFact,因此该值是递归的,Scala无法确定其类型,因此无法确定操作符的正确性。

你需要明确在这里!

答案 2 :(得分:1)

下面的代码编译正常:

package it.onof.scalaDemo

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:Int = a.!
        println("factorial of " + a + " is " + aFact)
  }
}