有没有办法在数据类构造时转换属性的值?

时间:2018-03-29 17:13:37

标签: kotlin data-class

创建数据类时,我经常发现我想要转换其中一个属性,通常是对其进行规范化或制作防御性副本。例如,我希望productCode始终为小写:

data class Product(val productCode: String)

我尝试添加一个init块,希望Kotlin足够聪明,让我手动处理构造函数参数赋值给属性:

data class Product(val productCode: String) {
    init {
        this.productCode = productCode.toLowerCase()
    }
}

但它将此视为重新分配。

我宁愿不必亲自编写equals / hashCode / toString / copy,而且IDE生成的方法也不是更好。

有没有办法在数据类中转换构造函数参数?

2 个答案:

答案 0 :(得分:7)

没有。要使相等和toString起作用,属性必须位于the primary constructor

然而,您可以创建工厂方法:

data class Product private constructor(val productCode: String) {

  companion object Factory {
     fun create(productCode: String) : Product {
        return Product(productCode.toLowerCase())
     }
  }
}

通过制作构造函数private,您可以强制使用此create方法。

如果您希望得到“hacky”,您可以通过将create重命名为invoke假装您还在调用构造函数并使其成为operator函数:

data class Product private constructor(val productCode: String) {

    companion object {

        operator fun invoke(productCode: String): Product {
            return Product(productCode.toLowerCase())
        }
    }
}

致电Product("foo")会调用invoke方法。

注意:构造函数仍然通过copy方法公开,请参阅https://youtrack.jetbrains.com/issue/KT-11914

答案 1 :(得分:2)

怎么样?
sealed class Product {
    abstract val productCode: String

    private data class Product(override val productCode: String) : your.package.Product()

    companion object {
        operator fun invoke(productCode: String): your.package.Product = 
            Product(productCode.toLowerCase())
    }
}

data class的所有优点,而不会暴露copy。否定的是必须在额外的时间重复属性名称。