问题 Scala类扩展{}


我偶然遇到了奇怪的Scala语法编译:

class Some extends {
  def hi = println("hi")
}

专家:

  • 它是Scala支持的官方语法吗?
  • 这是否意味着简单地扩展 Object
  • 它是否与“鸭子打字”有关?
  • 你知道有趣或棘手的用法吗?

谢谢。


3149
2017-07-19 05:02


起源



答案:


这实际上是Scala语法中的一个奇怪的怪癖。一个无关紧要的 extends 在开始上课之前允许。以下是相关部分 Scala语法摘要

ClassDef          ::=  id [TypeParamClause] {ConstrAnnotation} [AccessModifier] 
                       ClassParamClauses ClassTemplateOpt 
ClassTemplateOpt  ::=  ‘extends’ ClassTemplate | [[‘extends’] TemplateBody]
ClassTemplate     ::=  [EarlyDefs] ClassParents [TemplateBody]

ClassTemplateOpt 是类的参数之后的一切,在这种情况下一切都来自 extends 向前。通常使用 extends 是第一个轮换 ClassTemplateOpt,与 extends 由父母或早期初始化者遵循。但是,早期初始化程序不能包含 def,并且无法将大括号的内容解释为父级。它不能是结构类型,因为 hi 有一个具体的定义。

第二次交替允许类参数紧跟在类主体之后,而不使用 extends。但是,可选 extends 被允许。该 extends 在OP的代码中就是一个例子,并且完全等同于没有可选扩展的相同代码:

class Some {
  def hi = println("hi")
}

6
2017-07-20 13:27





这实际上只是一个语法上的意外(我认为)。 Scala允许 早期定义 看起来像

class Some extends {
  ...
} with ATrait

所以解析器也接受了 class Some extends { ... } 这相当于 class Some { ... }  (资源)


6
2017-07-19 08:08



看来,预先初始化/早期定义不允许声明函数。执行以下操作将无法编译:trait ATrait; class Some使用ATrait扩展{def hi = println(“hi”)} - Karl


答案:


这实际上是Scala语法中的一个奇怪的怪癖。一个无关紧要的 extends 在开始上课之前允许。以下是相关部分 Scala语法摘要

ClassDef          ::=  id [TypeParamClause] {ConstrAnnotation} [AccessModifier] 
                       ClassParamClauses ClassTemplateOpt 
ClassTemplateOpt  ::=  ‘extends’ ClassTemplate | [[‘extends’] TemplateBody]
ClassTemplate     ::=  [EarlyDefs] ClassParents [TemplateBody]

ClassTemplateOpt 是类的参数之后的一切,在这种情况下一切都来自 extends 向前。通常使用 extends 是第一个轮换 ClassTemplateOpt,与 extends 由父母或早期初始化者遵循。但是,早期初始化程序不能包含 def,并且无法将大括号的内容解释为父级。它不能是结构类型,因为 hi 有一个具体的定义。

第二次交替允许类参数紧跟在类主体之后,而不使用 extends。但是,可选 extends 被允许。该 extends 在OP的代码中就是一个例子,并且完全等同于没有可选扩展的相同代码:

class Some {
  def hi = println("hi")
}

6
2017-07-20 13:27





这实际上只是一个语法上的意外(我认为)。 Scala允许 早期定义 看起来像

class Some extends {
  ...
} with ATrait

所以解析器也接受了 class Some extends { ... } 这相当于 class Some { ... }  (资源)


6
2017-07-19 08:08



看来,预先初始化/早期定义不允许声明函数。执行以下操作将无法编译:trait ATrait; class Some使用ATrait扩展{def hi = println(“hi”)} - Karl


是的,这是Scala的结构类型或更常见的鸭子打字。

object LoudDuck {
    def quack(): String = "QUACK"
}

object QuietDuck {
    def quack(): String = "quack"
}

object CowDuck {
    def quack(): String = "moo"
}

def quackMyDuck(duck: { def quack(): String }) {
    println(duck.quack())
}

scala>quackMyDuck(LoudDuck)
QUACK

scala>

scala>quackMyDuck(QuietDuck)
quack

scala>

scala>quackMyDuck(CowDuck)
moo

您还可以使用“type”关键字声明结构类型。

type Duck = { def quack(): String }

def quackMyDuck(duck: Duck) {
    println(duck.quack())
}

-1
2017-07-19 05:50



你给出的例子 是 结构类型,但问题不是。 - Alexey Romanov
考虑 type T = { def hi = println("hi") }  - 它不编译,因为结构类型不能有定义。 - wingedsubmariner