title | date | author | tags | keywords | categories | reward | reward_title | reward_wechat | reward_alipay | source_url | translator | translator_url |
---|---|---|---|---|---|---|---|---|---|---|---|---|
[译]Feedback Request: Limitations on Data Classes |
2015-09-09 09:26:00 -0700 |
Andrey Breslav |
官方动态 |
false |
Have a nice Kotlin! |
M13 即将到来,我们计划稍后一点。这是对 Kotlin 未来变化的反馈请求。 我们希望比以后提供 Kotlin 1.0,这使我们推迟了一些我们没有足够的信心的设计选择。今天我们讨论数据类。
的概念 数据类 当简单地存储数据时,已被证明非常有用。所有你需要的是说:
{% raw %}
{% endraw %}data class Foo(val a: A, val b: B)
{% raw %}
{% endraw %}并且您可以免费获得equals()/ hashCode()
,toString()
,copy()
和组件函数。
最常见的用例类似于魅力,但数据类与其他语言功能的交互可能会导致令人惊讶的结果。
例如,如果我想扩展一个数据类呢?如果派生类也是数据类怎么办?
{% raw %}
{% endraw %}open data class Base(val a: A, val b: B)
data class Derived(a: A, b: B, val c: C) : Base(a, b)
{% raw %}
{% endraw %}现在,equals()
或copy()
在Derived
中的工作如何?所有众所周知的问题立即出现:
- 如果一个 Base 的实例等于 Derived 的实例,如果它们对于 a 和 b 具有相同的值?
- 等于()的传递性怎么样?
- 如果我通过 Base 类型的引用复制 Derived 的实例?
以及组件功能如何启用 多重声明 ?在这种基本情况下,c
简单地成为Derived
**中的第三个组件似乎或多或少是逻辑的:
{% raw %}
{% endraw %}val (a, b, c) = Derived(...)
{% raw %}
{% endraw %}但没有什么能阻止我们写这样的东西:
{% raw %}
{% endraw %}data class Derived(b: B, a: A, val c: C) : Base(a, b)
{% raw %}
{% endraw %}请注意,参数顺序相反:first b
,比a
。现在还不清楚。而且可能会变得更糟:
{% raw %}
{% endraw %}data class Derived(val c: C, b: B, a: A) : Base(a, b)
{% raw %}
{% endraw %}现在,第一个c
,继承的component1():A
只是一个冲突,它不是一个覆盖,但是这样的重载也不合法。
这些只是一些例子,还有更多的问题,大小。
一方面,我们不确定是否有一个优雅的继承涉及数据类的设计。我们有一些草图,但没有一个看起来很有前途。 另一方面,我们现在想完成语言设计,能够发货 1.0。 所以,我们决定限制数据类,以排除 1.0 中的所有有问题的案例,以便我们稍后再回来,也许解除一些限制。
我们将要做以下事情:
- 允许从接口继承数据类
- 禁止从其他类继承数据类
- 禁止开放的数据类(即其他类不能扩展数据类)
- 禁止内部数据类(不清楚等于()/ hashCode()应该如何处理外部引用)
- 允许本地数据类(闭包不是结构化的,所以 equals()/ hashCode()可以忽略它)
- 要求数据类的所有主构造函数的 val / var
- 需要至少一个数据类的主要构造函数参数
- 允许数据类的私有主构造函数参数
- var 在各方面都与 val 一样好(他们参与 equals()/ hashCode()等)
- 在数据类的主构造函数参数中禁止 varargs
再次,这个清单中的一些限制可能会稍后解决,但现在我们不想处理这些情况。
这是 JVM 上一个长期以来的众所周知的问题:equals()
对于数组和集合的工作方式不同。集合在结构上进行了比较,而数组不是,equals()
对于他们来说只是采用参考平等:this === other
。
目前,Kotlin 数据类在这个问题上表现不好:
- 如果你声明一个组件是一个数组,它将在结构上进行比较,
- 但是如果它是一个多维数组(数组数组),那么子阵列将被比较(通过数组上的 equals()),
- 并且如果组件的声明类型是 Any 或 T,但在运行时它恰好是一个数组,equals()也将被调用。
这种行为是不一致的,我们决定按照最小阻力的路径解决它:
- 总是使用 equals()作为所有其他对象来比较数组
所以,每当你说
- arr1 == arr2
- arr 在 setOfArrays 中
- DataClass(arr1)== DataClass(arr2)
- 或沿着这些线路的其他任何东西,
你可以通过equals()
来比较数组,也就是说。
我们很乐意解决与集合不一致的问题,但唯一平凡的修复方式似乎是将它固定在 Java 中,这超出了任何人的力量,AFAIK <img alt =“:)”class =“wp-smiley” data-recalc-dims =“1”src =“https://i2.wp.com/blog.jetbrains.com/kotlin/wp-includes/images/smilies/simple-smile.png?w=640&ssl= 1“style =”height:1em; max-height:1em;“/>
请分享您对建议变更的意见。我们或多或少对数组有所了解,对数据类的限制也很有信心,但是对于更广泛的用例来说,总是一个好主意。 谢谢你的帮助!