【问题标题】:Changing multiple attributes of a data class with a Lens使用镜头更改数据类的多个属性
【发布时间】:2019-09-25 18:25:39
【问题描述】:

我正在 Kotlin 中尝试使用 Lenses,我想知道是否有一种优雅的方法可以同时更改一个对象的多个属性。假设我的域看起来像这样:

@optics
data class Parameters(
    val duration: Int,
    val length: Int) {
  companion object
}

@optics
data class Calculation(
    val product: String
    val parameters: Parameters) {
  companion object
}

感谢@optics注解,编辑单个字段很容易:

val calculation = Calculation(product = "prod", Parameters(duration = 10, length = 15))

Calculation.product.modify(calculation) { selectedProduct }
Calculation.parameters.duration(calculation) { newDuration() }
Calculation.parameters.length(calculation) { 10 }

这些镜头单独工作时效果很好,但是当我想同时应用这三个变换时,应该使用哪种正确的模式?我可以使用 var 并每次都覆盖 calculation,但这对我来说并不符合习惯。

【问题讨论】:

    标签: kotlin functional-programming arrow-kt


    【解决方案1】:

    Arrow 目前不公开此类功能,但您可以轻松地自己编写通用解决方案。

    下面的 sn-p 演示了它是如何实现的,您可以添加其他方法来编写从 Lens<S, Tuple2<FA, FB>>Lens<S, Tuple3<FA, FB, FC>> 等。

    @optics data class Char(val name: String, val health: Int) {
      companion object
    }
    
    infix fun <S, FA, FB> Lens<S, FA>.aside(other: Lens<S, FB>): Lens<S, Tuple2<FA, FB>> = object : Lens<S, Tuple2<FA, FB>> {
      override fun get(s: S): Tuple2<FA, FB> = Tuple2(this@aside.get(s), other.get(s))
      override fun set(s: S, b: Tuple2<FA, FB>): S = other.set(this@aside.set(s, b.a), b.b)
    }
    
    fun main() {
      val original = Char("", 0)
      val charName: Lens<Char, String> = Char.name
      val charHealth: Lens<Char, Int> = Char.health
      val charNameAndHealth: Lens<Char, Tuple2<String, Int>> = charName.aside(charHealth)
    
      charNameAndHealth.modify(original) { Tuple2("Test", 30) }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-16
      • 2019-05-13
      • 1970-01-01
      相关资源
      最近更新 更多