#scala #collections #multiple-inheritance
#scala #Коллекции #множественное наследование
Вопрос:
Приведенный ниже код генерирует: Хэш-код
имени для хэш-кода
имени для хэш-кода
имени равен
ID =0
import scala.collection.mutable
object TestTraits {
def main(args: Array[String]): Unit = {
val toto0 = new Person(0,"toto")
val toto1 = new Person(1,"toto")
val peoples = mutable.Set.empty[PersonID]
peoples.add(toto0)
peoples.add(toto1)
peoples.foreach(_.showID)
//peoples.foreach(_.saySomething)//won't compile'
}
}
trait Name{
var theName=""
override def hashCode(): Int = {
println("Name's hashCode")
var hash = 5;
hash = 71 * hash this.theName.##;
hash
//super.hashCode()//infinite loop
}
override def equals(that: Any): Boolean = {
println("Name's equals")
that match {
case that: Name => this.theName.equals(that.theName)
case _ => false
}
}
}
abstract class PersonID{
val idNumber: Int
override def hashCode(): Int = {
println("PersonID's hashCode")
super.##
}
override def equals(that: Any): Boolean = {
println("PersonID's equals")
that match {
case that: PersonID => this.eq(that)
case _ => false
}
}
def showID: Unit = {
println("ID=" idNumber)
}
}
class Person(val id:Int, val s:String) extends {
val idNumber=id
} with PersonID with Name {
/*override def hashCode(): Int = {
println("Person's hashCode")
super.## //infinite loop !!
}
override def equals(that: Any): Boolean = {
println("Person's equals")
that match {
case that: Person => this.eq(that)
case _ => false
}
}*/
theName=s
def saySomething: Unit = {
print("Hello, my name is " theName ", ")
showID
}
}
Поскольку «peoples» — это набор PersonID, я ожидал следующего вывода:
Хэш-код идентификатора пользователя
Хэш-код идентификатора пользователя
ID=0
ID=1
Может ли кто-нибудь объяснить это поведение и как сделать то, что я ожидал (то есть иметь класс с «equals» на основе значений полей, за исключением случаев помещения экземпляра в набор [PersonID])
Еще одна загадка заключается в том, почему я получаю бесконечные циклы, когда я использую super.hashCode() в моем пользовательском хэш-коде?
PS: Я использую предварительно инициализированный абстрактный элемент, потому что он мне нужен в моем реальном варианте использования…
Ответ №1:
Вместо этого я получаю это:
Name's hashCode
Name's hashCode
Name's equals
ID=0
Это происходит потому, что Name
это последняя черта в инициализации, поэтому она переопределяет hashCode
и equals
будет вызвана первой. Вы хотели Set
вызывать методы на основе статического типа (то есть того, что было объявлено), что просто не так, как работает OO. Если бы это было правдой, наследование и переопределение были бы практически бесполезны.
Что касается того, как выполнить то, что вы хотите… вы не можете. Было бы неплохо, если бы существовал класс, Set
который принимал Equal[A]
тип class, но его нет. Возможно, у Scalaz это есть.
Кстати, есть вызов super.##
, который считается незаконным в Scala 2.9.0.rc2. Я пока не уверен, что это значит.
Комментарии:
1. Спасибо за ваш ответ, теперь ясно, что я должен реализовать это по-другому.
Ответ №2:
Еще одна загадка заключается в том, почему я получаю бесконечные циклы, когда я использую super.hashCode() в моем пользовательском хэш-коде?
Помимо стандартных цифр, вся реализация ## заключается в вызове хэш-кода.
В вашей реализации хэш-кода вы вызываете (или пытаетесь вызвать) ##.
Загадка раскрыта!
Комментарии:
1. Я думаю, что рекурсия не должна выполняться, поскольку я намеревался вызвать super.hashCode (), а не this.hashCode(). Как и вы, я думал, что хэш-код и ## на самом деле являются одним и тем же методом, но после изменения ## с помощью hashCode() бесконечный цикл исчезает…
2. Я почти уверен в том, как это работает, поскольку я это написал. ## вызывает хэш-код. Я не уверен, какая часть этого вам непонятна, иначе я бы уточнил подробнее.
3. Неясным был тот факт, что я получаю бесконечный цикл, несмотря на вызов super. ## . Другой парень на форуме scala дал мне следующее объяснение: «Ваши бесконечные циклы вызваны использованием super. ## из определения метода хэш-кода. Вызов x.## приведет к вызову ScalaRunTime.hash(x), который, в свою очередь, для потомка AnyRef вызовет x.hashCode(). Использование super здесь вам не поможет. Если вы используете super.hashCode(), то вы получите поведение, которое, похоже, ожидаете.»