Kotlin 有没有办法在数据类构造时转换属性的值?
当创建一个数据类时,我经常发现我想要转换其中一个属性,通常是对其进行规范化或制作一个防御性副本。例如,这里我希望Kotlin 有没有办法在数据类构造时转换属性的值?,kotlin,data-class,Kotlin,Data Class,当创建一个数据类时,我经常发现我想要转换其中一个属性,通常是对其进行规范化或制作一个防御性副本。例如,这里我希望productCode始终为小写: data class Product(val productCode: String) 我尝试添加一个init块,希望Kotlin足够聪明,可以让我手动处理构造函数参数对属性的赋值: data class Product(val productCode: String) { init { this.productCode =
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生成的方法也不是很好
是否有任何方法可以转换数据类中的构造函数参数?否。要使equality和toString起作用,属性必须在中 但是,您可以做的是创建一个工厂方法:
data class Product private constructor(val productCode: String) {
companion object Factory {
fun create(productCode: String) : Product {
return Product(productCode.toLowerCase())
}
}
}
通过使构造函数私有
可以强制使用此创建
方法
如果你想“黑客”,你可以通过将create
重命名为invoke
并使其成为操作符
函数,假装你仍在调用构造函数:
data class Product private constructor(val productCode: String) {
companion object {
operator fun invoke(productCode: String): Product {
return Product(productCode.toLowerCase())
}
}
}
调用Product(“foo”)
将调用invoke
方法
注意:构造函数仍然通过
copy
方法公开,请参见如何
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())
}
}
数据类
的所有优点,无需公开复制
。负片必须额外重复属性名称。工厂方法是一个有趣的想法,但是copy
充当后门的事实是一个相当严重的缺陷。我不希望一个具有未规范化属性的对象可能存在。我可以在init
中添加一个require(…)
,但是到那时,额外的代码量已经达到了使用常规类可能不是那么糟糕的程度。我不认为像这样使用invoke
一点都不黑。非常好的一个!挑剔:toString
方法将打印ProductImpl(productCode=“…”)
而不是Product
。哦,你是对的。编辑了答案以解决此问题。我认为这确实很聪明,但最终必须声明完整的属性集4次,这与使用常规类并自己实现equals
、hashCode
和toString
是一样的。需要规范化的属性越多,常规类方法得到的时间就越长,虽然这种方法保持不变,但仍然非常接近。但是在equals
和friends(IMO)中重复属性的最大问题是,添加新属性时,您可能会错过一个或忘记编辑所有属性。在这种方法中,其中一个位置缺少属性是编译错误。