简体   繁体   English

如何从Scala中的重写方法返回正确的类型?

[英]How to return correct type from an overriden method in Scala?

As a newbie in Scala, I have stumbled on this seemingly easy point of SubClassing and Overriding methods. 作为Scala中的新手,我偶然发现了SubClassing和Overriding方法的这一看似简单的观点。

I have specialized a Set thus: 我专门设置了一个Set,因此:

    class SpecializedSet [T](s:Int, b: Boolean) (implicit ordering: Ordering [T]) extends TreeSet [T] { 
      override def + (t: T): SpecializedSet [T] = {

           if (this.isEmpty) {

              s = s + 1

              // I want to add an element to the Set
              super.+ (t) 

           }
           ....
       }

At the site of using this class, I do: 在使用此类的站点上,我这样做:

       class Driver {

         var e = new SpecializedSet [MyEarlierDefinedType](3,false);

         ......

         val elem1 = new MyEarlierDefinedType()

         e = e + eleme1 

         ......
     }

The compiler immediately complains: 编译器立即抱怨:

type mismatch; 类型不匹配; found : scala.collection.immutable.TreeSet[T] required: org.personal.exercises.SpecializedSet[T] 找到:scala.collection.immutable.TreeSet [T]必需:org.personal.exercises.SpecializedSet [T]

I understand that the overridden '+' method has to return a 'SpecializedSet' type - a Subtype - and a mere call to super.+() doesn't achieve that. 我知道被覆盖的'+'方法必须返回'SpecializedSet'类型-子类型-仅调用super。+()并不能实现这一点。

It is not the same TreeSet that super.+() returns, it is a new TreeSet created in its place. super。+()返回的不是同一个TreeSet,而是在其位置创建的新TreeSet。 I am thinking that I have to now create a new instance of SpecializedSet() myself, using this new TreeSet. 我在想,我现在必须使用这个新的TreeSet自己创建一个SpecializedSet()的新实例。 I am stuck here. 我被困在这里。 How do I create a new SpecializedSet(), using a TreeSet which is its Supertype ? 如何创建一个新的SpecializedSet(),使用一个TreeSet 这是它的超类型 What is the idiom in the Scala world to use in such cases? 在这种情况下,Scala世界中有哪些惯用语? Is use of asInstanceOf() the most appropriate and short answer here? 在这里使用asInstanceOf()是最合适,最简短的答案吗? But, isn't use of that method discouraged all along? 但是,是不是一直不鼓励使用该方法?

Do I have to create a companion object of SpecializedSet defining an apply() method therein? 我是否必须创建在其中定义apply()方法的SpecializedSet的伴随对象? Alternatively, do I have to go much deeper and use the concept of Traits described in Scala: how to write method that returns object typed to implementation type of receiver and Subclasses and return types and other related links? 或者,我是否必须更深入并使用Scala中描述的特征的概念:如何编写将对象类型返回到接收方子类的 实现类型 以及返回类型和其他相关链接的方法? Or, follow the more complicated direction of creating Builder s like in http://www.scala-lang.org/docu/files/collections-api/collections-impl.html ? 或者,遵循http://www.scala-lang.org/docu/files/collections-api/collections-impl.html中那样创建Builder的更复杂的方向?

I have gone through this question (and answers) too: Extending a Scala collection - and they are certainly useful - but somehow I think there is more to it than I have understood. 我也经历了这个问题(和答案): 扩展Scala集合 -它们肯定有用-但以某种方式,我认为它包含的内容超出了我的理解。 For example, one of the solutions in that link is to explicitly mention the type of Baseclass in the function signature, thus: 例如,该链接中的解决方案之一是在函数签名中显式提及Baseclass的类型,因此:

      override def + (t: T): TreeSet [T] = { // instead of SpecializedSet 
             ......

But, then isn't it a violation of the expectation of the caller of the method, in a way? 但是,在某种程度上,这是否违反了方法调用者的期望? I am confused. 我很困惑。

Does the solution have to be so involved as outlined in these links? 解决方案是否必须像这些链接中所概述的那样参与其中? What is the obvious point that I am missing? 我想念的明显点是什么? Any pointer will be helpful. 任何指针都会有所帮助。 I have searched to quite a good extent but if my question is a duplicate, please bear with me and direct me. 我已经进行了很大程度的搜索,但是如果我的问题是重复的,请忍受并指导我。

I would prefer to extend the corresponding trait and use the class through composition instead of direct inheritance: 我更愿意扩展相应的特征,并通过组合而不是直接继承来使用类:

class SpecializedSet[T](s: Int, b: Boolean)(implicit ordering: Ordering[T]) extends SortedSet[T] {
  private var ts = new TreeSet[T]()
  override def +(t: T): SpecializedSet[T] = {
    ts += t
    this
  }
  override def -(t: T): SpecializedSet[T] = {
    ts -= t
    this
  }
  override def contains(t: T): Boolean = ts.contains(t)
  override def iterator(): Iterator[T] = ts.iterator
  override def ordering(): Ordering[T] = ts.ordering
  override def rangeImpl(from: Option[T], until: Option[T]) = ts.rangeImpl(from, until)
}

I think this approach is more newbie friendly since it avoids direct class inheritance and (direct) calls to super. 我认为这种方法更便于新手使用,因为它避免了直接的类继承和对Super的(直接)调用。 The drawback of this very simple solution is that we introduced mutability. 这种非常简单的解决方案的缺点是我们引入了可变性。 This could be solved by redesigning the constructor a bit so that it is possible to make the member a val and really return a new modified SpecializedSet instance instead of this . 可以通过重新设计构造函数来解决此问题,以便可以将成员设为val并真正返回一个新的修改后的SpecializedSet实例来代替this实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM