Kotlin коллекций: Можете ли вы, при желании, задать ключи классов данных по идентичности? - PullRequest
1 голос
/ 28 мая 2020

Kotlin имеет очень полезную функцию классов данных, которые имеют семантику значений, то есть компилятор автоматически сгенерирует equals и hashCode на основе значений полей. Например, вы можете представить абстрактное синтаксическое дерево с такими объявлениями, как

data class Plus(val a: Term, val b: Term) : Term()

. Но когда приходит время преобразовать абстрактное синтаксическое дерево в форму SSA, идентичность внезапно начинает иметь значение; это вхождение a+b не следует путать с это вхождение.

В идеале необходимы классы данных, которые можно обрабатывать с семантикой значений в одном контексте и ссылке семантика в другом.

Частично это можно сделать, используя операторы == по сравнению с === для сравнения значений и сравнения идентичностей. Другая половина изображения - это коллекции, наборы и карты, которые теперь должны иногда иметь sh свои ключи по идентификатору, а не по содержимому.

Есть ли способ переопределить обработку ключей по умолчанию в наборах и карты, чтобы сказать, на этот раз используют идентичность, а не содержимое?

1 Ответ

1 голос
/ 28 мая 2020

На мой взгляд, это не семантика значений и ссылочная семантика, а идентичность.

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

Если вы хотите смоделировать сущность, которая имеет идентичность, то есть стабильную логическую сущность, связанную с серией различных значений во времени, вы должны использовать обычный класс и определить, какова его идентичность. Это может быть uuid или адрес памяти.

Также возможно смоделировать сущность, используя класс данных. Вы можете определить это так:

data class Plus(val id: Long, val a: Term, val b: Term) : Term()

Или больше похоже на предложение @marstran

data class Entity(val id: Long, val value: Any)

Решения @ marstran и @gidds практичны и выполняют свою работу, но я думаю, вы должны осторожно, чтобы не запутать ваш код. В IdentityHashMap есть даже это предупреждение javado c: Этот класс не является универсальной реализацией Map! Хотя этот класс реализует интерфейс Map, он намеренно нарушает общий контракт Map, который требует использования метода equals при сравнении объектов. Этот класс разработан для использования только в редких случаях, когда требуется семантика равенства ссылок.

...