When creating a data class I frequently find that I want to transform one of the properties, usually to normalize it or to make a defensive copy. For example, here I want productCode to always be lowercase:

data class Product(val productCode: String)

我try 添加一个init%的挡路,希望Kotlin 足够聪明,让我手动处理构造函数参数对属性的赋值:

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

but it treats this as a reassignment.

我宁愿不必手工编写equals/hashCode/toString/copy,IDE生成的方法也不会更好.

Is there any way to transform constructor parameters in a data class?

推荐答案

No. For equality and toString to work, the properties need to be in the primary constructor.

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

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

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

By making the constructor private you force usage of this create method.

If you want to get 'hacky', you can pretend you're still calling the constructor, by renaming create to invoke and making it an operator function:

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

Kotlin相关问答推荐

测试Compose Multiplatform UI时,为另一个文件设置ComposeRule()

Jetpack Compose中的数字 Select 器问题

将带大括号和不带大括号的Lambda值赋给@Composable函数

Kotlin-stdlib中的模拟扩展函数

为什么Kotlin协程程序即使有延迟也能输出?

Kotlin编译器如何决定是否可以在任何给定点调用Suspend方法?

在构造函数中创建内部类实例时,只能使用包含类的接收器调用内部类的构造函数

可组合项在返回后返回时组合导航句柄

Kotlin 启动与启动(Dispatchers.Default)

Kotlin 中的as Long和.toLong()有什么区别?

如何创建扩展函数isNullOrEmpty?

Mixin 在 Jackson 中添加 defaultImpl 不起作用

类型是什么意

在协程中等待侦听器内的数据

主机名不能为空

在java代码中使用kotlin库

Spring Boot:更改属性占位符符号

在android的默认浏览器 Select 列表中添加我的浏览器?

Kotlin,什么时候按map授权?

从 java 活动 *.java 启动 kotlin 活动 *.kt?