Kotlin集合:您可以选择按标识为数据类设置键吗?

Kotlin集合:您可以选择按标识为数据类设置键吗?,kotlin,collections,data-class,Kotlin,Collections,Data Class,Kotlin具有数据类的非常有用的特性,这些数据类具有值语义,即编译器将根据字段的值自动生成equals和hashCode。例如,您可以用如下声明表示抽象语法树 data class Plus(val a: Term, val b: Term) : Term() 但当需要将抽象语法树转换为SSA形式时,身份突然变得重要起来;不可将此a+b事件与该事件混淆 理想情况下需要的是可以在一个上下文中用值语义处理,在另一个上下文中用引用语义处理的数据类 这一部分可以通过使用==与===运算符进行值相等与

Kotlin具有数据类的非常有用的特性,这些数据类具有值语义,即编译器将根据字段的值自动生成
equals
hashCode
。例如,您可以用如下声明表示抽象语法树

data class Plus(val a: Term, val b: Term) : Term()
但当需要将抽象语法树转换为SSA形式时,身份突然变得重要起来;不可将此
a+b
事件与该事件混淆

理想情况下需要的是可以在一个上下文中用值语义处理,在另一个上下文中用引用语义处理的数据类

这一部分可以通过使用
==
===
运算符进行值相等与标识比较来实现。图片的另一半是集合、集合和地图,现在它们有时需要按身份而不是内容散列密钥


有没有一种方法可以覆盖集合和映射中键的默认处理方式,也就是说,这次使用的是标识而不是内容?

我认为这不是值语义与引用语义,而是标识

数据类表示一个值。一个值是不可变的,并且没有标识,这意味着两个值是相同的当且仅当它们具有相同的内容时。这就是为什么编译器可以自动生成equals和hashcode

如果您想对具有标识的实体(即,随时间变化与一系列不同值关联的稳定逻辑实体)建模,则应使用常规类并定义其标识。它可以是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 javadoc中也有这样的警告:这个类不是通用的映射实现!虽然该类实现了Map接口,但它故意违反了Map的一般约定,该约定要求在比较对象时使用equals方法。此类仅在少数需要引用相等语义的情况下使用。

也许您可以将值包装在一个容器中,该容器使用其内容的标识实现相等和哈希代码?类似于
class-IdentityContainer(val-value:T)
with
override-fun-equals(o:Any)=o是IdentityContainer&&o.value==value
。这不是一个完整的答案,但您知道吗?否则,如果您确实需要从值语义开始,您可能最好将对象转换为其他类型(新对象或按照marstran的注释包装)。@gidds I不是。这看起来是一个很好的解决方案,谢谢!