You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin如何将抽象值作为抽象函数的默认参数?

解决密封类子类数据类的自定义copy方法问题

你遇到的问题本质是抽象函数无法直接使用抽象属性作为默认参数——编译器在处理抽象函数定义时,无法确定item和balance的具体值,所以会提示未初始化错误。要实现你想要的“只传修改参数、复用原有值”的效果,可以按以下方式调整代码:

核心思路

  • 抽象层只定义copyScreenState的参数列表,不设置默认值
  • 在每个数据类子类的实现中,为参数添加默认值,默认值直接引用当前实例的属性(this.item/this.balance)
  • 对于有专属额外参数的子类,同样为专属参数添加默认值,保证复用原有属性

修改后的代码示例

sealed class ScreenState {
    abstract val item: DTOPurchasableItem
    abstract val balance: String?
    // 抽象函数不设置默认参数
    abstract fun copyScreenState(item: DTOPurchasableItem, balance: String?): ScreenState

    // 普通子类:NotEnoughMoney
    data class NotEnoughMoney(
        override val item: DTOPurchasableItem,
        override val balance: String?
    ) : ScreenState() {
        // 实现时添加默认参数,引用当前实例的属性
        override fun copyScreenState(
            item: DTOPurchasableItem = this.item,
            balance: String? = this.balance
        ): ScreenState = copy(item = item, balance = balance)
    }

    // 普通子类:ItemAlreadyOwned
    data class ItemAlreadyOwned(
        override val item: DTOPurchasableItem,
        override val balance: String?
    ) : ScreenState() {
        override fun copyScreenState(
            item: DTOPurchasableItem = this.item,
            balance: String? = this.balance
        ): ScreenState = copy(item = item, balance = balance)
    }

    // 带专属参数的子类示例:PurchasedSuccess
    data class PurchasedSuccess(
        override val item: DTOPurchasableItem,
        override val balance: String?,
        // 专属额外参数
        val timestamp: Long
    ) : ScreenState() {
        // 实现时包含专属参数的默认值(如果需要支持修改专属参数,可重载方法)
        override fun copyScreenState(
            item: DTOPurchasableItem = this.item,
            balance: String? = this.balance
        ): ScreenState = copy(item = item, balance = balance, timestamp = this.timestamp)

        // 重载方法:支持修改专属参数
        fun copyScreenState(
            item: DTOPurchasableItem = this.item,
            balance: String? = this.balance,
            timestamp: Long = this.timestamp
        ): ScreenState = copy(item = item, balance = balance, timestamp = timestamp)
    }
}

调用示例

完全符合你想要的使用方式:

val screenState = ScreenState.NotEnoughMoney(item = generateItem(), balance = "2000")
// 只修改balance,复用原有item
val newState = screenState.copyScreenState(balance = "100")

// 带专属参数的子类调用示例
val successState = ScreenState.PurchasedSuccess(generateItem(), "1500", System.currentTimeMillis())
// 只修改balance,复用item和timestamp
val newSuccessState = successState.copyScreenState(balance = "1000")
// 修改balance和timestamp,复用item
val updatedSuccessState = successState.copyScreenState(balance = "800", timestamp = System.currentTimeMillis())

这样既保留了密封类的状态区分能力,又实现了数据类的便捷copy特性,同时支持子类扩展专属参数的场景。

内容的提问来源于stack exchange,提问作者Felipe Ribeiro R. Magalhaes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 06:48:37