【问题标题】:Is there not an idiomatic way to have a (secondary) constructor that derives values for the primary constructor in Kotlin?有没有一种惯用的方式来拥有一个(辅助)构造函数来为 Kotlin 中的主构造函数派生值?
【发布时间】:2018-09-24 17:34:46
【问题描述】:

我有一个简单的 Kotlin 类:

data class ValveSpan(val begin:Duration, val end:Duration, val key:String):Comparable<ValveSpan> {
    ...
}

因为它是一个数据类,我必须有一个主构造函数,其中包含一个或多个值。没关系,我喜欢它简洁的表达方式。

但是当我想创建一个从 doc 类对象(类似于 JSON)填充一个辅助构造函数时,它变得很奇怪:

constructor(doc:TSON):this(doc["begin"].duration!!, doc["end"].duration!!, doc["valves"].sequence!!.first()!!.string!!) {
    // do nothing here, because, uh, I had to do it all in the delegated primary????
}

基本上,辅助构造函数的目的是获取输入,为主构造函数计算一些值,然后使用这些值调用主构造函数。但似乎我必须在主构造函数中内联它们。随着推导变得越来越复杂,它变得越来越复杂。我真的很想写这样的东西:

constructor(doc:TSON) {
    var sanitizedBegin =  doc["begin"].duration ?: 0.minutes
    var sanitizedEnd = doc["end"].duration ?: 0.minutes
    var sanitizedKey = doc["valves"].sequence?.firstOrNull()?.string ?: ""
    primaryConstructor(sanitizedBegin, sanitizedEnd, sanitizedKey)
}

有没有办法委派给主构造函数,而不必内联进行所有桥接计算?

【问题讨论】:

  • 不。 Java 实际上也不支持(至少我上次尝试过)
  • 给男人希望的方法。 :/ 我正在努力成为一个更好的 iOS/Android swift/kotlin 多语言者。 Kotlin 很酷。但有时我只想打我的头,直到它在键盘上流血。
  • 使用伴生对象非常适合这个用例,它就像类的工厂一样,你可以有尽可能多的派生逻辑。
  • @AhmedAshrafGamal 看起来像什么?
  • 我必须在伴侣上有静态工厂方法,对吧?基本上 fun doc(doc:TSON) : ValveSpan { ... } 代替 constructor 关键字?然后不是通过看起来像构造函数的东西来创建它们(例如ValveSpan(doc),我会使用ValveSpan.doc(doc)

标签: kotlin


【解决方案1】:

您可以为此目的使用伴随对象:

data class ValveSpan(val begin:Duration, val end:Duration, val key:String) {
    companion object {
        fun fromDoc(doc:TSON): ValveSpan {
            var sanitizedBegin =  doc["begin"].duration ?: 0.minutes
            var sanitizedEnd = doc["end"].duration ?: 0.minutes
            var sanitizedKey = doc["valves"].sequence?.firstOrNull()?.string ?: ""
            return ValveSpan(sanitizedBegin, sanitizedEnd, sanitizedKey)
        }
    }
}

用法:

ValveSpan.fromDoc(doc)

【讨论】:

    【解决方案2】:

    要添加@ahmed-ashraf-gamal 的answer,您还可以通过引入一个在伴随对象上定义调用运算符的伴随对象来模拟从 ValveSpan 客户端调用构造函数。例如:

    data class ValveSpan(val begin:Duration, val end:Duration, val key:String) {
        companion object {
            operator fun invoke(doc:TSON): ValveSpan {
                var sanitizedBegin =  doc["begin"].duration ?: 0.minutes
                var sanitizedEnd = doc["end"].duration ?: 0.minutes
                var sanitizedKey = doc["valves"].sequence?.firstOrNull()?.string ?: ""
                return ValveSpan(sanitizedBegin, sanitizedEnd, sanitizedKey)
            }
        }
    }
    

    这将允许您致电ValveSpan(doc)

    【讨论】:

    • 不知道,很好:)
    猜你喜欢
    • 2019-01-10
    • 1970-01-01
    • 2012-12-16
    • 2017-03-12
    • 1970-01-01
    • 2015-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多