В поисках чего-то другого, совершенно случайно, я наткнулся на несколько комментариев о том, насколько дьявольским является наследование case-классов. Там была штука под названием ProductN
, негодяи и короли, эльфы и волшебники, и как какое-то очень желательное свойство теряется при наследовании классов case. Так что же не так с наследованием case-классов?
Что *так* не так с наследованием класса case?
Ответы (2)
Это не совсем так. А это хуже лжи.
Как упоминалось aepurniet, в любом случае преемник класса, который сужает область определения, должен переопределить равенство, потому что сопоставление с образцом должно работать точно так же, как равенство (если попытаться сопоставить Point
с ColoredPoint
, то он не будет совпадать, так как color
не существует).
Это дает понимание того, как можно реализовать равенство иерархии классов case.
case class Point(x: Int, y: Int)
case class ColoredPoint(x: Int, y: Int, c: Color) extends Point(x, y)
Point(0, 0) equals ColoredPoint(0, 0, RED) // false
Point(0, 0) equals ColoredPoint(0, 0, null) // true
ColoredPoint(0, 0, RED) equals Point(0, 0) // false
ColoredPoint(0, 0, null) equals Point(0, 0) // true
В конце концов можно удовлетворить требования отношения равенства даже для преемника класса case (без переопределения равенства).
case class ColoredPoint(x: Int, y: Int, c: String)
class RedPoint(x: Int, y: Int) extends ColoredPoint(x, y, "red")
class GreenPoint(x: Int, y: Int) extends ColoredPoint(x, y, "green")
val colored = ColoredPoint(0, 0, "red")
val red1 = new RedPoint(0, 0)
val red2 = new RedPoint(0, 0)
val green = new GreenPoint(0, 0)
red1 equals colored // true
red2 equals colored // true
red1 equals red2 // true
colored equals green // false
red1 equals green // false
red2 equals green // false
def foo(p: GreenPoint) = ???
person
user1303559
schedule
06.04.2016
person
schedule
А как насчет небольшого уточнения :) ?
- person Ashkan Kh. Nazary; 22.06.2012
Кажется, что такая асимметричная эквивалентность была бы полезна в парадигме объектно-ориентированного программирования, точно так же, как на уровне типа
ColoredPoint
является Point
, но не наоборот. Хотя, возможно, придется называть это как-то иначе, чем equals
... может быть, subEquals
?
- person Luigi Plinge; 22.06.2012
@LuigiPlinge, возможно,
canReplace
, supersedes
, specifies
или overrides
для обратной связи? Все, что указывает на >=
-ность (или >:
, если хотите) этого. Мне кажется, гораздо проще назвать его с точки зрения >=
, а не <=
.
- person Dan Burton; 23.06.2012
Если подумать, такую вещь было бы сложно (невозможно?) реализовать из-за возможности повышения уровня, так что, возможно, это не такая уж хорошая идея.
- person Luigi Plinge; 23.06.2012
Этот пример не компилируется в 2.10.2
- person expert; 03.08.2013
универсальное равенство тривиально легко реализовать, чтобы удовлетворить равенство, сделать класс членом сравнения. копирование выглядит как просто ошибка, и взаимодействие с сопоставлением шаблонов должно работать, как и для иерархий классов без регистра.
- person aepurniet; 18.06.2015
Точно, ColoredPoint.class != Point.class?
- person Lodewijk Bogaards; 15.07.2015
case class
получает equals
только тогда, когда ни один из его родителей не переопределяет его, поэтому в этом случае ColoredPoint
будет использовать equals
/hashCode
Point
(я не знаю, было ли это уже в 2012 году), который является симметричным (и отражающим и транзитивным). Вы можете возразить, что ColoredPoint(0, 0, RED) == ColoredPoint(0, 0, GREEN)
неинтуитивен, и я соглашусь, но проблема не в наследовании case-класса: у вас точно такая же проблема, если Point
является классом, отличным от case
, переопределяющим equals
. copy
больше проблема.
- person Alexey Romanov; 24.08.2016
Кто-нибудь может расширить этот ответ, предоставив передовое решение проблемы ColoredPoint, пожалуйста?
- person ; 01.07.2017