gpt4 book ai didi

scala - Scala 中的类型安全通用案例类更新

转载 作者:行者123 更新时间:2023-12-04 21:40:26 25 4
gpt4 key购买 nike

我正在尝试编写一些代码来跟踪记录的更改并在以后应用它们。在动态语言中,我只需保留 List[(String, Any)] 对的日志,然后在我最终决定提交更改时简单地将它们作为对原始记录的更新应用。

我需要能够自省(introspection)更新,所以更新函数列表是不合适的。

在 Scala 中,使用反射是相当简单的,但是我想实现一个类型安全的版本。

我的第一次尝试是尝试无形。如果我们知道特定的类型,这很有效。

import shapeless._
import record._
import syntax.singleton._

case class Person(name:String, age:Int)
val bob = Person("Bob", 31)
val gen = LabelledGeneric[Person]

val updated = gen.from( gen.to(bob) + ('age ->> 32) )

// Result: Person("Bob", 32)

但是,我无法弄清楚如何使这项工作通用。
trait Record[T]
def update( ??? ):T
}

鉴于 shapeless 处理此问题的方式,我不确定这是否可能?

如果我接受很多样板,作为一个糟糕的男人版本,我可以按照以下方式做一些事情。
object Contact {
sealed trait Field[T]
case object Name extends Field[String]
case object Age extends Field[Int]
}

// A typeclass would be cleaner, but too verbose for this simple example.
case class Contact(...) extends Record[Contact, Contact.Field] {
def update[T]( field:Contact.Field[T], value:T ) = field match {
case Contact.Name => contact.copy( name = value )
case Contact.Age => contact.copy( age = value )
}
}

然而,这并不是特别优雅,并且需要大量样板文件。我可能可以编写自己的宏来处理这个问题,但这似乎是一件相当普遍的事情——有没有办法用 Shapeless 或类似的宏库来处理这个问题?

最佳答案

使用类的整个实例作为更新怎么样?

case class Contact(name: String, age: Int) 
case class ContactUpdate(name: Option[String] = None, age: Option[Int] = None)

object Contact {
update(target: Contact, delta: ContactUpdate) = Contact(
delta.name.getOrElse(target.name)
target.age.getOrElse(delta.age)
)
}
// also, optionally this:
object ContactUpdate {
apply(name: String) = ContactUpdate(name = Option(name))
apply(age: Int) = ContactUpdate(age = Option(age))
}

我认为,如果您想要真正类型安全的解决方案,这是最干净、最易读的解决方案,而且实现起来可能最痛苦,因为您不需要处理记录、镜头和单个字段描述符,只需 ContactUpdate(name="foo")创建一个更新, updates.map(Contact.update(target, _)) 按顺序应用它们。

关于scala - Scala 中的类型安全通用案例类更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27739803/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com