为什么我不能指定特征的子类?

发布于 2024-10-25 04:56:44 字数 410 浏览 2 评论 0原文

scala> class A
defined class A

scala> trait T extends A { val t = 1 }
defined trait T

//why can I do this?
scala> class B extends T
defined class B

scala> new B
res0: B = B@2e9c76

scala> res0.t
res1: Int = 1

我认为当您编写trait T extends A时,它使得您只能将trait T放在作为A子类的类上>。那为什么我可以把它放在B上呢?这只是当你混合它的时候吗?为什么在声明类时这是不可能的?

scala> class A
defined class A

scala> trait T extends A { val t = 1 }
defined trait T

//why can I do this?
scala> class B extends T
defined class B

scala> new B
res0: B = B@2e9c76

scala> res0.t
res1: Int = 1

I thought that when you write trait T extends A, it makes it so you can only put trait T on a class that is a subclass of A. Why can I put it on B, then? Is this only for when you mix it in? Why is this not possible when declaring the class?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

ぶ宁プ宁ぶ 2024-11-01 04:56:44

“它使得你只能输入特征
T 属于 A 的子类”

您想要的功能是自我类型注释。另请参阅 Daniel Sobral 对这个问题的回答:自我类型和特质子类之间有什么区别? --> 查找链接依赖注入和蛋糕模式。

trait A { def t: Int }
trait B {
  this: A => // requires that a concrete implementation mixes in from A
  def t2: Int = t // ...and therefore we can safely access t from A
}

// strangely this doesn't work (why??)
def test(b: B): Int = b.t

// however this does
def test2(b: B): Int = b.t2

// this doesn't work (as expected)
class C extends B

// and this conforms to the self-type
class D extends B with A { def t = 1 }

"it makes it so you can only put trait
T on a class that is a subclass of A"

The feature you want is a self-type annotation. See also Daniel Sobral's answer to this question : What is the difference between self-types and trait subclasses? --> look for the links to dependancy-injection and cake-pattern.

trait A { def t: Int }
trait B {
  this: A => // requires that a concrete implementation mixes in from A
  def t2: Int = t // ...and therefore we can safely access t from A
}

// strangely this doesn't work (why??)
def test(b: B): Int = b.t

// however this does
def test2(b: B): Int = b.t2

// this doesn't work (as expected)
class C extends B

// and this conforms to the self-type
class D extends B with A { def t = 1 }
呆头 2024-11-01 04:56:44

你不能做的是:

scala> class A2
defined class A2

scala> class B extends A2 with T
<console>:8: error: illegal inheritance; superclass A2
 is not a subclass of the superclass A
 of the mixin trait T
       class B extends A2 with T
                               ^

实际上,编写class B extends T与编写class B extends A with T是一样的。

What you can’t do is:

scala> class A2
defined class A2

scala> class B extends A2 with T
<console>:8: error: illegal inheritance; superclass A2
 is not a subclass of the superclass A
 of the mixin trait T
       class B extends A2 with T
                               ^

Actually, writing class B extends T is the same as writing class B extends A with T.

决绝 2024-11-01 04:56:44

你只是对特质是什么感到困惑。说class B extends T只是意味着您将特征的功能“混合”到B的类定义中。因此,T或其父类和特征中定义的所有内容都可以在B.

You're simply confused about what a trait is. Saying class B extends T simply means that you're "mixing in" the functionality of the trait to the class definition of B. So, everything defined in T or it's parent classes and traits, is available in B.

眼角的笑意。 2024-11-01 04:56:44

您可以指定特征的子类,尽管它是多余的。
考虑到此代码

object TraitPulling {
  class A {
    val a = 0
    println("I am constructor of A")
  }
  trait T extends A { val t = 1 }
  class B extends T
  class C extends A with T    // though no T with A
  List(new T {}, new B(), new C()).foreach { e =>
    println(s"t: ${e.t}, a: ${e.a}")
  }
}

TraitPulling

给出了以下输出,

I am constructor of A
I am constructor of A
I am constructor of A
t: 1, a: 0
t: 1, a: 0
t: 1, a: 0

我们可以推断,由于类 A 的内容被实例化,因为它是隐含的(通过trait T extends A),因此这三种形式在语义上是等效的。

You can specify the trait's subclass, though it will be redundant.
Considering that this code

object TraitPulling {
  class A {
    val a = 0
    println("I am constructor of A")
  }
  trait T extends A { val t = 1 }
  class B extends T
  class C extends A with T    // though no T with A
  List(new T {}, new B(), new C()).foreach { e =>
    println(s"t: ${e.t}, a: ${e.a}")
  }
}

TraitPulling

gives the following output

I am constructor of A
I am constructor of A
I am constructor of A
t: 1, a: 0
t: 1, a: 0
t: 1, a: 0

we can deduce that since class A's content gets instantiated because it is implied (by trait T extends A), the three forms are semantically equivalent.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文