代码之家  ›  专栏  ›  技术社区  ›  onof

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

  •  5
  • onof  · 技术社区  · 14 年前
    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 回复  |  直到 12 年前
        1
  •  10
  •   Daniel C. Sobral    14 年前

    所有这些关于递归函数和类型的讨论都是一条红鲱鱼。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
    

    所以在编译器解析你的程序时,这看起来像是一个有效的中缀表达式。后来,它注意到这些类型不匹配,但现在回头看看是否可以推断出分号已经太迟了。

        2
  •  6
  •   Dario    14 年前

    因为不然 ! 可以解释为二进制表达式

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

    但是由于正确的操作数包含 aFact 它本身的值是递归的,Scala不能确定它的类型,因此不能确定操作符的正确固定性。

        3
  •  1
  •   Jaydeep Patel    14 年前

    下面的代码编译得很好:

    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)
      }
    }