12

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

data class Product(val productCode: String)

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

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

但它将此视为重新分配。

我宁愿不必手动编写equals/// hashCode,而且IDE 生成的方法并没有好多少toStringcopy

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

4

2 回答 2

12

不。要使相等和 toString 起作用,属性需要在主构造函数中。

但是,您可以做的是创建一个工厂方法:

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

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

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

如果您想获得“hacky”,您可以假装您仍在调用构造函数,方法是重命名createinvoke使其成为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

于 2018-03-29T17:24:25.953 回答
3

关于什么

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。消极的一面是必须额外重复属性名称。

于 2018-03-30T12:23:31.537 回答