Scala 为什么父列表中的第一个基类必须是非特征类?

Scala 为什么父列表中的第一个基类必须是非特征类?,scala,inheritance,traits,Scala,Inheritance,Traits,在中,据说在类模板中,sc扩展了mt1,mt2,…,mtn 每个特征参考mti必须表示一个特征。相比之下 超类构造函数sc通常指的是一个不是 特质可以写一个以字母开头的家长列表 特征参考,例如mt1和……和mtn。在这种情况下 父项列表被隐式扩展以包括父项的超类型 mt1作为第一个父类型。新的超类型必须至少有一个 不接受参数的构造函数。在下文中,我们将 始终假定已执行此隐式扩展,以便 模板的第一个父类是常规超类 构造函数,而不是特征引用 如果我理解正确,我认为这意味着: trait Base1

在中,据说在类模板中,
sc扩展了mt1,mt2,…,mtn

每个特征参考mti必须表示一个特征。相比之下 超类构造函数sc通常指的是一个不是 特质可以写一个以字母开头的家长列表 特征参考,例如mt1和……和mtn。在这种情况下 父项列表被隐式扩展以包括父项的超类型 mt1作为第一个父类型。新的超类型必须至少有一个 不接受参数的构造函数。在下文中,我们将 始终假定已执行此隐式扩展,以便 模板的第一个父类是常规超类 构造函数,而不是特征引用

如果我理解正确,我认为这意味着:

trait Base1 {}
trait Base2 {}
class Sub extends Base1 with Base2 {}
将隐式扩展到:

trait Base1 {}
trait Base2 {}
class Sub extends Object with Base1 with Base2 {}
我的问题是:

  • 我的理解正确吗
  • 此要求(父列表中的第一个子类必须是非特征类)和隐式扩展是否仅适用于类模板(例如
    类子扩展Mt1、Mt2
    )或特征模板(例如
    特征子扩展Mt1、Mt2
  • 为什么这个需求和隐式扩展是必要的
  • 1) 基本上是的,你的理解是正确的。与Java中一样,每个类都继承自
    Java.lang.Object
    (Scala中的
    AnyRef
    )。因此,由于您正在定义一个具体的类,因此您将隐式地继承
    对象
    。如果您与REPL进行核对,您会得到:

    scala> trait Base1 {}
    defined trait Base1
    
    scala> trait Base2 {}
    defined trait Base2
    
    scala> class Sub extends Base1 with Base2 {}
    defined class Sub
    
    scala> classOf[Sub].getSuperclass
    res0: Class[_ >: Sub] = class java.lang.Object
    
    2) 是的,从规范中的“特征”一段来看,这也适用于他们。在“模板”一段中,我们有:

    新的超类型必须至少有一个不带参数的构造函数

    然后在“特质”一段:

    与普通类不同,traits不能有构造函数参数。此外,没有构造函数参数传递给trait的超类。这是不必要的,因为特征是在超类初始化之后初始化的

    假设特征D定义了C类型实例x的某些方面(即D是C的基类)。那么x中D的实际超类型是由L(C)中继承D的所有基类组成的复合类型

    这是定义没有参数的基本构造函数所必需的

    3) 根据答案(2),需要定义基本构造函数(1)基本上是的,您的理解是正确的。与Java中一样,每个类都继承自
    Java.lang.Object
    (Scala中的
    AnyRef
    )。因此,由于您正在定义一个具体的类,因此您将隐式地继承
    对象
    。如果您与REPL进行核对,您会得到:

    scala> trait Base1 {}
    defined trait Base1
    
    scala> trait Base2 {}
    defined trait Base2
    
    scala> class Sub extends Base1 with Base2 {}
    defined class Sub
    
    scala> classOf[Sub].getSuperclass
    res0: Class[_ >: Sub] = class java.lang.Object
    
    2) 是的,从规范中的“特征”一段来看,这也适用于他们。在“模板”一段中,我们有:

    新的超类型必须至少有一个不带参数的构造函数

    然后在“特质”一段:

    与普通类不同,traits不能有构造函数参数。此外,没有构造函数参数传递给trait的超类。这是不必要的,因为特征是在超类初始化之后初始化的

    假设特征D定义了C类型实例x的某些方面(即D是C的基类)。那么x中D的实际超类型是由L(C)中继承D的所有基类组成的复合类型

    这是定义没有参数的基本构造函数所必需的


    3) 根据答案(2),需要定义基本构造函数

    免责声明:我不是,也从来不是“Scala设计委员会”或类似组织的成员,所以“为什么?”问题的答案主要是猜测,但我认为这是一个有用的答案

    免责声明#2:我写这篇文章花了好几个小时,拍了好几次,所以可能不太一致

    免责声明#3(对未来读者来说,这是一个可耻的自我推销):如果你觉得这个很长的答案很有用,你也可以看看黄立夫关于类似主题的另一个问题

    简短回答

    这是一个复杂的问题,我不认为有一个好的简短的答案,除非你已经知道答案是什么。虽然我的真实答案很长,但以下是我最好的简短答案:

    为什么父列表中的第一个基类必须是非特征类

    因为必须只有一个非特征基类,如果它总是第一个基类,那么事情就更容易了

  • 我的理解正确吗
  • 是的,你隐含的例子就是将会发生的事情。然而,我不确定它是否显示了对该主题的充分理解

  • 此要求(父列表中的第一个子类必须是非特征类)和隐式扩展是否仅适用于类模板(例如
    类子扩展Mt1、Mt2
    )或特征模板(例如
    特征子扩展Mt1、Mt2
  • 不,特性也会发生隐式扩展。实际上,你怎么能期望
    Mt1
    有自己的“超类型”被提升到扩展它的类中呢

    事实上,这里有两个不明显的例子证明了这一点:

    示例#1

    这个例子失败了,因为规范说

    extends子句
    用mt1mt1扩展scsc,用mtnmtn扩展scsc
    可以省略,在这种情况下
    扩展scala。假定为AnyRef

    因此
    TNo
    实际上扩展了与
    AnyVal
    不兼容的
    AnyRef

    示例2

    再次
    ChildBad
    失败,因为
    TSecond
    需要
    cssecond
    TFirst
    仅提供
    CFirst
    作为基类

  • 为什么这个需求和隐式扩展是必要的
  • 有三个主要原因:<
    class CFirst
    class CSecond extends CFirst
    
    // did you know that traits can extend classes as well?
    trait TFirst extends CFirst
    trait TSecond extends CSecond
    
    // works
    class ChildGood extends TSecond with TFirst
    // fails 
    // illegal inheritance; superclass CFirst is not a subclass of the superclass CSecond of the mixin trait TSecond
    class ChildBad extends TFirst with TSecond
    
    trait Achilles {
      def getAchillesPos: Int
      def stepAchilles(): Unit
    }
    
    class AchillesImpl(var achillesPos: Int) extends Achilles {
      def getAchillesPos: Int = achillesPos
      def stepAchilles(): Unit = {
        achillesPos += 2
      }
    }
    
    class TortoiseImpl(var tortoisePos: Int) {      
      def getTortoisePos: Int = tortoisePos
      def stepTortoise(): Unit = {
        tortoisePos += 1
      }
    }
    
    class AchillesAndTortoise(handicap: Int) extends AchillesImpl(0) with TortoiseImpl(handicap) {
      def catchTortoise(): Int = {
        var time = 0
        while (getAchillesPos < getTortoisePos) {
          time += 1
          stepAchilles()
          stepTortoise()
        }
        time 
      }
    }
    
    class CBase {
      def getValue = 2
    }
    trait TFirst extends CBase {
      override def getValue = super.getValue + 1
    }
    trait TSecond extends CFirst {
      override def getValue = super.getValue * 2
    }
    class CThird extends CBase with TSecond {
      override def getValue = 100 - super.getValue
    }
    
    class Child extends TFirst with TSecond with CThird
    
    trait TFourth extends CThird
    class AnotherChild extends TFirst with TSecond with TFourth