2009-11-30 4 views
2

У меня возникли проблемы с расширением базового класса, который расширяет упорядоченный [Base]. Мой производный класс не может расширять Ordered [Derived], поэтому его нельзя использовать в качестве ключа в TreeMap. Если я создам TreeMap [Base], а затем просто переопределяю сравнение в Derived, которое работает, но это не то, что я хочу. Я хотел бы иметь возможность иметь производный класс в качестве ключа. Есть ли способ обойти это?Расширить класс scala, который распространяется по заказу

case class A(x: Int) extends Ordered[A] { 
    def compare(that: A) = x.compare(that.x) 
} 

// Won't compile 
// case class B(val y : Int) extends A(1) with Ordered[B] { 
// def compare(that: B) = x.compare(that.x) match { 
//  case 0 => y.compare(that.y) 
//  case res => res 
// } 
// } 

// Compiles but can't be used to define a TreeMap key 
case class B(y: Int) extends A(1) { 
    override def compare(that: A) = that match { 
    case b: B => x.compare(b.x) match { 
     case 0 => y.compare(b.y) 
     case res => res 
    } 
    case _: A => super.compare(that) 
    } 
} 

def main(args: Array[String]) { 
    TreeMap[B, Int]() // Won't compile 
} 

Редактировать

This discussion в списке рассылки кажется Scala очень актуальным, но она теряет меня немного.

ответ

4

Вы можете использовать преобразование типа из B в упорядоченном [B]:

class OrderedB(me : B) extends Ordered[B]{ 
    def compare(that: B) = me compare that 
} 
collection.immutable.TreeMap.empty[B, Int](new OrderedB(_)) 

Я думаю, что B всегда должен быть подтипом А, подразумевает Орден [A] whoes типа А инвариантно. Он не может определить второй метод сравнения для реализации Order [B] с тем же типом, что и метод сравнения из Ordered [A].

В качестве альтернативы можно определить неявные версии типа из В упорядоченном [B]:

implicit def orderedA2orderedB[B <: A with Ordered[A]](b : B) : Ordered[B] = b.asInstanceOf[Ordered[B]] 
collection.immutable.TreeMap[B, Int]() 

Это должно быть действительным. Я не знаю, как выразить это в системе типов без бросков.

+0

Спасибо за помощь Томас. Я надеялся, что может быть какая-то магия Scala, которую я пропустил, и это позволило ей работать. Не прибегая к существенному прохождению в компараторе. Является ли это только мне или это кажется очень ограниченным и весьма раздражающим? Или это можно ожидать? – Dave

+0

При работе с Ordered [T] вы обычно должны использовать связь <%, чтобы запросить, чтобы вы хотели, чтобы объект, который заказывает объект. Если вы этого не сделаете, такие типы, как Int (которые не распространяют AnyRef, поэтому они не могут реализовать какие-либо черты), также не будут работать с вашим контейнером. Обратите внимание, что этот ответ касается только Scala 2.7 –

+0

@Dave - я добавил неявную версию преобразования типов. Это не идеально, так как требуется бросок. –

2

Вы можете поместить неявное упорядочение [B] в объеме где-то, как это:

object BOrdering extends Ordering[B] { 
    def compare(a: B, b: B) = a.compare(b) 
    } 
    implicit val bo = BOrdering 
    TreeMap[B, Int]() // Now it works! 

EDIT: Это только в Scala 2.8 (спасибо, Кен)

+1

Только в Scala 2.8 –

3

Значение Ordered принимает параметр. Параметр типа, предоставленный, но он работает так же, как и любой другой параметр. Когда вы увеличиваете его дважды, в базовом классе и в подклассе, вы не «импортируете» две версии Ordered. Вместо этого происходит линеаризация классов, и вы импортируете ее только один раз. По этой причине вы не можете передать ему два разных параметра.

Теперь, есть причина, почему TreeMap не требует subclass из Ordered, просто переход от вашего класса к Ordered его. Именно такие вещи возможны. Вместо того, чтобы распространять эти вещи напрямую, вы должны имплицировать:

scala> class A(val x: Int) 
defined class A 

scala> class B(x : Int, val y : Int) extends A(x) 
defined class B 

scala> import scala.collection.immutable.TreeMap 
import scala.collection.immutable.TreeMap 

scala> class AOrd(a: A) extends Ordered[A] { 
    | def compare(that: A) = a.x.compare(that.x) 
    | } 
defined class AOrd 

scala> object AOrd { 
    | implicit def toAOrd(a: A) = new AOrd(a) 
    | } 
defined module AOrd 

scala> class BOrd(b: B) extends Ordered[B] { 
    | def compare(that: B) = b.x.compare(that.x) match { 
    |  case 0 => b.y.compare(that.y) 
    |  case res => res 
    | } 
    | } 
defined class BOrd 

scala> object BOrd { 
    | implicit def toBOrd(b: B) = new BOrd(b) 
    | } 
defined module BOrd 

scala> import AOrd._ 
import AOrd._ 

scala> import BOrd._ 
import BOrd._ 

scala> TreeMap[B, Int]() 
res1: scala.collection.immutable.SortedMap[B,Int] = Map() 
+0

Как вы поддерживаете естественный порядок для A и B? Всегда импортировать AOrd._ & BOrd._ нехорошо, и каждый a1: A

+0

Каким образом вы создаете эти хорошие списки сеансов переводчика? – ziggystar

+0

Скала-интерпретатор: '$ scala'. –

Смежные вопросы