覆盖 Kotlin 数据类的 getter [英] Override getter for Kotlin data class

查看:25
本文介绍了覆盖 Kotlin 数据类的 getter的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定以下 Kotlin 类:

Given the following Kotlin class:

data class Test(val value: Int)

如何覆盖 Int 获取器,使其在值为负时返回 0?

How would I override the Int getter so that it returns 0 if the value negative?

如果这是不可能的,有哪些技术可以达到合适的结果?

If this isn't possible, what are some techniques to achieve a suitable result?

推荐答案

在每天花费几乎一整年时间编写 Kotlin 之后,我发现尝试像这样覆盖数据类是一种不好的做法.对此有 3 种有效方法,在我介绍它们之后,我将解释为什么其他答案建议的方法很糟糕.

After spending almost a full year of writing Kotlin daily I've found that attempting to override data classes like this is a bad practice. There are 3 valid approaches to this, and after I present them, I'll explain why the approach other answers have suggested is bad.

  1. 让创建数据类的业务逻辑在调用具有错误值的构造函数之前将值更改为 0 或更大.这可能是大多数情况下的最佳方法.

  1. Have your business logic that creates the data class alter the value to be 0 or greater before calling the constructor with the bad value. This is probably the best approach for most cases.

不要使用数据类.使用常规的 class 并让您的 IDE 为您生成 equalshashCode 方法(或者不,如果您不需要它们).是的,如果对象的任何属性发生更改,您将必须重新生成它,但您可以完全控制对象.

Don't use a data class. Use a regular class and have your IDE generate the equals and hashCode methods for you (or don't, if you don't need them). Yes, you'll have to re-generate it if any of the properties are changed on the object, but you are left with total control of the object.

class Test(value: Int) {
  val value: Int = value
    get() = if (field < 0) 0 else field

  override fun equals(other: Any?): Boolean {
    if (this === other) return true
    if (other !is Test) return false
    return true
  }

  override fun hashCode(): Int {
    return javaClass.hashCode()
  }
}

  • 在对象上创建一个额外的安全属性来执行您想要的操作,而不是拥有一个被有效覆盖的私有值.

  • Create an additional safe property on the object that does what you want instead of having a private value that's effectively overriden.

    data class Test(val value: Int) {
      val safeValue: Int
        get() = if (value < 0) 0 else value
    }
    

  • 其他答案建议的糟糕方法:

    data class Test(private val _value: Int) {
      val value: Int
        get() = if (_value < 0) 0 else _value
    }
    

    这种方法的问题在于数据类并不是真正意义上的像这样改变数据.它们实际上只是用于保存数据.像这样覆盖数据类的 getter 意味着 Test(0)Test(-1) 不会 equal 并且会有不同的 hashCode,但是当你调用 .value 时,它们会得到相同的结果.这是不一致的,虽然它可能对你有用,但你团队中的其他人看到这是一个数据类,可能会意外地误用它,而没有意识到你是如何改变它/使它无法按预期工作的(即这种方法不会t 在 MapSet 中正常工作).

    The problem with this approach is that data classes aren't really meant for altering data like this. They are really just for holding data. Overriding the getter for a data class like this would mean that Test(0) and Test(-1) wouldn't equal one another and would have different hashCodes, but when you called .value, they would have the same result. This is inconsistent, and while it may work for you, other people on your team who see this is a data class, may accidentally misuse it without realizing how you've altered it / made it not work as expected (i.e. this approach wouldn't work correctly in a Map or a Set).

    这篇关于覆盖 Kotlin 数据类的 getter的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆