创建数据类时,我经常发现我想要转换其中一个属性,通常是对其进行规范化或制作防御性副本。例如,我希望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生成的方法也不是更好。
有没有办法在数据类中转换构造函数参数?
答案 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
。否定的是必须在额外的时间重复属性名称。