Будучи новичком в Scala, я наткнулся на этот, казалось бы, простой момент методов подкласса и переопределения.
Я специализировал 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)
}
....
}
На месте использования этого класса я делаю:
class Driver {
var e = new SpecializedSet [MyEarlierDefinedType](3,false);
......
val elem1 = new MyEarlierDefinedType()
e = e + eleme1
......
}
Компилятор сразу жалуется:
несоответствие типов; найдено: scala.collection.immutable.TreeSet[T] требуется: org.personal.exercises.SpecializedSet[T]
Я понимаю, что переопределенный метод «+» должен возвращать тип «SpecializedSet» — подтип — и простой вызов super.+() не достигает этого.
Это не тот же TreeSet, который возвращает super.+(), это новый TreeSet, созданный на его месте. Я думаю, что теперь я должен сам создать новый экземпляр SpecializedSet(), используя этот новый TreeSet. Я застрял здесь. Как создать новый SpecializedSet(), используя TreeSet, который является его супертипом? Какую идиому в мире Scala использовать в таких случаях? Является ли использование asInstanceOf() наиболее подходящим и коротким ответом здесь? Но разве использование этого метода не обескураживает все это время?
Должен ли я создавать сопутствующий объект SpecializedSet, определяя в нем метод apply()? В качестве альтернативы мне нужно пойти намного глубже и использовать концепцию Traits, описанную в Scala: как написать метод, который возвращает объект, типизированный для типа реализации получателя и Подклассы и возвращаемые типы и другие связанные ссылки? Или следуйте более сложному направлению создания Builder, как в http://www.scala-lang.org/docu/files/collections-api/collections-impl.html.?
Я также рассмотрел этот вопрос (и ответы): Расширение коллекции Scala - и они безусловно полезно, но почему-то мне кажется, что это нечто большее, чем я понял. Например, одно из решений в этой ссылке — явно указать тип базового класса в сигнатуре функции, например:
override def + (t: T): TreeSet [T] = { // instead of SpecializedSet
......
Но тогда разве это не нарушение ожиданий вызывающего метода? Я смущен.
Должно ли решение быть настолько сложным, как указано в этих ссылках? Каков очевидный момент, который я упускаю? Любой указатель будет полезен. Я провел довольно тщательный поиск, но если мой вопрос повторяется, пожалуйста, потерпите меня и направьте меня.