为什么类不能使用相同签名的方法扩展特征?

发布于 2024-08-12 19:20:25 字数 949 浏览 6 评论 0原文

为什么我会收到以下错误?如何解决它?

我假设由于 A 和 B 编译为(接口,类)对,因此在编译 C 时选择正确的静态方法调用来实现是一个问题。我希望优先级按照顺序排列。

scala> trait A { def hi = println("A") }
defined trait A

scala> trait B { def hi = println("B") }
defined trait B

scala> class C extends B with A
<console>:6: error: error overriding method hi in trait B of type => Unit;
 method hi in trait A of type => Unit needs `override' modifier
       class C extends B with A

scala> trait A { override def hi = println("A") }
<console>:4: error: method hi overrides nothing
       trait A {override def hi = println("A")}

请注意,在 Ruby 中这很有效:

>> module B; def hi; puts 'B'; end; end
=> nil
>> module A; def hi; puts 'A'; end; end
=> nil
>> class C; include A; include B; end
=> C
>> c = C.new
=> #<C:0xb7c51068>
>> c.hi
B
=> nil

Why do I get the error below? How to workaround it?

I assumed that since A and B compile to (interface,class) pairs, it's a matter of choosing the right static method call to implement when compiling C. I would expect the priority to be according to order.

scala> trait A { def hi = println("A") }
defined trait A

scala> trait B { def hi = println("B") }
defined trait B

scala> class C extends B with A
<console>:6: error: error overriding method hi in trait B of type => Unit;
 method hi in trait A of type => Unit needs `override' modifier
       class C extends B with A

scala> trait A { override def hi = println("A") }
<console>:4: error: method hi overrides nothing
       trait A {override def hi = println("A")}

Note that in Ruby this works well:

>> module B; def hi; puts 'B'; end; end
=> nil
>> module A; def hi; puts 'A'; end; end
=> nil
>> class C; include A; include B; end
=> C
>> c = C.new
=> #<C:0xb7c51068>
>> c.hi
B
=> nil

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

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

发布评论

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

评论(5

晚雾 2024-08-19 19:20:25

这在 2.8 和 2.11 中适用于我,并且允许您不干扰特征 AB

trait A { def hi = println("A") }
trait B { def hi = println("B") }

class C extends A with B {
  override def hi = super[B].hi
  def howdy = super[A].hi // if you still want A#hi available
}

object App extends Application {
  (new C).hi // prints "B"
}

This works for me in 2.8 and 2.11, and would allow you to be non-intrusive in traits A or B:

trait A { def hi = println("A") }
trait B { def hi = println("B") }

class C extends A with B {
  override def hi = super[B].hi
  def howdy = super[A].hi // if you still want A#hi available
}

object App extends Application {
  (new C).hi // prints "B"
}
属性 2024-08-19 19:20:25

您可以使用一个通用的基本特征,例如 Base,如下所示:

trait Base {def hi: Unit}
trait A extends Base {override def hi = println("A")}
trait B extends Base {override def hi = println("B")}
class C extends A with B

通过类型层次结构,调用 hi 的结果如下(注意使用 {} 来实例化特征):

scala> (new A {}).hi
A

scala> (new B {}).hi
B

scala> (new C).hi
B

You could use a common base trait, say Base, as follows:

trait Base {def hi: Unit}
trait A extends Base {override def hi = println("A")}
trait B extends Base {override def hi = println("B")}
class C extends A with B

With the type hierarchy the result of calling hi's is as follows (note the use of {} to instantiate the traits):

scala> (new A {}).hi
A

scala> (new B {}).hi
B

scala> (new C).hi
B
街角卖回忆 2024-08-19 19:20:25

特征向混合它的类添加方法。如果两个特征添加相同的方法,则该类最终将有两个相同的方法,当然,这是不可能发生的。

但是,如果该方法在特征中是私有的,则不会引起问题。如果您希望这些方法相互堆叠,您可以定义一个基本特征,然后在继承特征上进行抽象覆盖。然而,它需要一个类来定义该方法。下面是一个示例:

scala> trait Hi { def hi: Unit }
defined trait Hi

scala> trait A extends Hi { abstract override def hi = { println("A"); super.hi } }
defined trait A

scala> trait B extends Hi { abstract override def hi = { println("B"); super.hi } }
defined trait B

scala> class NoHi extends Hi { def hi = () }
defined class NoHi

scala> class C extends NoHi with B with A
defined class C

scala> new C().hi
A
B

但是,如果您确实希望每个特征有两个单独的方法,那么您需要组合而不是继承

A trait adds methods to the class that mixes it in. If two traits adds the same method, the class would end up with two identical methods, which, of course, can't happen.

If the method is private in the trait, however, it won't cause problem. And if you want the methods to stack over each other, you may define a base trait and then abstract override on the inheriting traits. It requires a class to define the method, however. Here is an example of this:

scala> trait Hi { def hi: Unit }
defined trait Hi

scala> trait A extends Hi { abstract override def hi = { println("A"); super.hi } }
defined trait A

scala> trait B extends Hi { abstract override def hi = { println("B"); super.hi } }
defined trait B

scala> class NoHi extends Hi { def hi = () }
defined class NoHi

scala> class C extends NoHi with B with A
defined class C

scala> new C().hi
A
B

If, however, you truly want two separate methods from each trait, then you'll need to compose instead of inherit.

何其悲哀 2024-08-19 19:20:25

这是钻石问题。应该继承哪一个方法 hi,是来自 A 的方法,还是来​​自 B 的方法?您可以按照 Don 的建议,通过使用共同的基本特征来解决这个问题。

This is the diamond problem. Which method hi should be inherited, the one from A, or the one from B? You can get around this as Don suggested, by using a common base trait.

深海少女心 2024-08-19 19:20:25

我遇到了同样的问题,我不喜欢创建一个中间特征,因为我可以使用相同的方法拥有 4,5 个甚至 6 个特征,因为它是包含 CRUD 操作(查找、创建...)的特征。此外,我只需要出于测试目的而将这些特征一起使用,并且我总是尝试尽可能避免修改项目的结构,只是为了使测试更容易。
所以我只是在不同的对象中实现了这些特征:

class somethingToTest {
  object AImpl extends ATrait 
  object BImpl extends BTrait

  val a = AImpl.methodDuplicated()
  val b = BImpl.methodDuplicated()
}

这可能不是使用特征的最聪明的方法,但它不需要对项目的代码进行任何更改,它只意味着在测试中需要更多的代码。

I had the same problem and I didn't like to have to create an intermediary trait because I can have 4,5 or even 6 traits with the same methods, because it is traits containing CRUD operations (find, create...). Furthermore I needed to use those trait together only for test purpose and I always try to avoid as much as possible to modify the structure of my project only to make my test easier.
So I simply implemented those traits in different objects :

class somethingToTest {
  object AImpl extends ATrait 
  object BImpl extends BTrait

  val a = AImpl.methodDuplicated()
  val b = BImpl.methodDuplicated()
}

It is probably not the most clever way to use traits but it doesn't require any change in the project's code, it only implies to have a bit more code in the tests.

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