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

Is there any way to transform the value of a property at data class construction time?

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

data class Product(val productCode: String)

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

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

但它将此视为重新分配。

我宁愿不必手动编写 equals/hashCode/toString/copy 并且 IDE 生成的方法并不是真的好多了。

有什么方法可以转换数据中的构造函数参数class?

没有。为了使 equality 和 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

怎么样

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())
    }
}

没有暴露copydata class的所有优点。否定的是必须额外重复 属性 个名字。