Kotlin 使用镜头更改数据类的多个属性

Kotlin 使用镜头更改数据类的多个属性,kotlin,functional-programming,arrow-kt,Kotlin,Functional Programming,Arrow Kt,我正在Kotlin中进行实验,我想知道是否有一种优雅的方法可以同时更改一个对象的多个属性。假设我的域名看起来像这样: @optics data class Parameters( val duration: Int, val length: Int) { companion object } @optics data class Calculation( val product: String val parameters: Parameters) {

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

@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
,每次只覆盖
计算
,但这对我来说并不太习惯。

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

下面的代码片段演示了如何实现它,您可以添加其他方法,从
Lens
Lens
等进行合成

@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) }
}
@optics数据类字符(val name:String,val health:Int){
伴星
}
中缀趣味镜头。旁白(其他:镜头):镜头=对象:镜头{
覆盖乐趣获取(s:s):Tuple2=Tuple2(this@aside.get(s) ,其他。获取(s))
覆盖乐趣集(s:s,b:Tuple2):s=other.set(this@aside.set(s,b.a),b.b)
}
主要内容(){
val original=Char(“,0)
val charName:Lens=Char.name
val charHealth:Lens=Char.health
val charName和health:Lens=charName.aside(charHealth)
修改(原始){Tuple2(“Test”,30)}
}