2011-10-05 3 views
2

По сути я хочу сделать что-то вроде этого:Могу ли я использовать привязку типа по абстрактному методу Scala, а затем «подтянуть» определение в подклассе?

class Shape 

class CoordSystem 
class C3D(val x: Double, y: Double, z: Double) extends CoordSystem 
class C2D(val x: Double, y: Double) extends CoordSystem 

abstract class Shape { 
    def getCoords[C <: CoordSystem]: List[C] 
} 

class Pyramid extends Shape { 
    def getCoords: List[C3D] = 
    List(new C3D(1,2,1), new C3D(1,1,1), new C3D(2,2,1), new C3D(2,1,1), new C3D(1.5,1.5,3)) 
} 
>> error: class Pyramid needs to be abstract, since method getCoords in class Shape of type [C <: CoordSystem]List[C] is not defined 

Я видел горстка различных идей на this answer, но ни один из них не кажется, вполне подходит для этого случая - потому что они, кажется, не подведи меня напишите код в другом месте, который относится к myShape.getCoords, как если бы он был правильно определен в подклассе Shape, возвращая список объектов из подкласса CoordSystem.

Я также нашел an interesting discussion about generics в списке рассылки Scala Lang, но не смог полностью привязать его к моей ситуации.

Любая помощь с благодарностью оценили!

ответ

9

Как о чем-то вроде этого:

class CoordSystem 
class C3D(val x: Double, y: Double, z: Double) extends CoordSystem 
class C2D(val x: Double, y: Double) extends CoordSystem 

trait ShapeLike[+C <: CoordSystem] { 
    def getCoords: List[C] 
} 

abstract class Shape extends ShapeLike[CoordSystem] 

class Pyramid extends Shape with ShapeLike[C3D] { 
    def getCoords: List[C3D] = 
    List(new C3D(1, 2, 1), new C3D(1, 1, 1), new C3D(2, 2, 1), new C3D(2, 1, 1), new C3D(1.5, 1.5, 3)) 
} 

Конечно, ничто не заставляет вас объявить дополнительный тип ShapeLike, чтобы сделать это; его цель - позволить вам использовать тип Shape без лишних дополнительных параметров.

Итак, на самом деле ответ на ваш вопрос, как указано в названии: вы можете «затянуть» границу типа параметра типа в подклассе, если он определен как параметр ковариантного типа в суперклассе; наоборот, вы можете «ослабить» границу типа контравариантного параметра типа.

+0

Большое спасибо Жан-Филипп - это сработало как шарм! –

2

Параметр типа является параметром типа, а в договоре суперкласса требуется, чтобы вы не затягивали его контракт - что делает его менее строгим, не будет нарушать контракт, хотя я не думаю, что это разрешено.

Однако вы можете сделать что-то еще: поместите тип внутри класса.

class Shape 

class CoordSystem 
class C3D(val x: Double, y: Double, z: Double) extends CoordSystem 
class C2D(val x: Double, y: Double) extends CoordSystem 

abstract class Shape { 
    type C <: CoordSystem 
    def getCoords: List[C] 
} 

class Pyramid extends Shape { 
    override type C = C3D 
    def getCoords: List[C3D] = 
    List(new C3D(1,2,1), new C3D(1,1,1), new C3D(2,2,1), new C3D(2,1,1), new C3D(1.5,1.5,3)) 
} 
+0

Спасибо Даниилу - я подумал об этом подходе (увидев его в другом посте). Но я не мог понять, как заставить его хорошо играть с отдельными классами, используя параметры типа Shape и CoordSystem. С подходом Жана-Филиппа я смог написать, например. 'Класс Blah [C <: CoordSystem, S <: Shape with ShapeLike [CS]', а затем использовать 'getCoords' для возврата' List [C] 'в метод Blah. Я не мог понять эквивалентный синтаксис с типом переопределения «внутреннего» класса. Имеет ли смысл мой комментарий? –

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