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)中重复属性的最大问题是,添加新属性时,您可能会错过一个或忘记编辑所有属性。在这种方法中,其中一个位置缺少属性是编译错误。