使用选项更新深度嵌套的案例 class

Update deeply nested case class with Options

我有一个 3 级嵌套案例 class 模型,其中有一堆选项代表数据库中的一些数据。它本质上是:

case class User(settings: Option[Settings])
case class Settings(keys: Option[List[KeySet]])
case class KeySet(privateKey: String, publicKey: String)

我了解如何使用一些理解或 flatMap (Scala Option object inside another Option object) 的链从中获取深层嵌套的字段,我也了解如何使用镜头库更新它,但我想弄清楚如何更新字段,即使树中的某些内容是 None,如果它们尚不存在,则自动生成 Somes。

例如,如果我想添加到 keys 列表但用户尚未设置任何 settings,我将如何处理?从某种意义上说,是否有可能自动创建一个 Some(settings) 字段和一个 Some(keys) 字段?

我知道如何通过大量模式匹配来做到这一点,但这似乎是错误的,因为 1. 代码向右漂移和 2. 非常不使用 mapflatMap很多选项。

是否可以单独使用镜头库?我在这里读到这可能是不可能的:https://github.com/julien-truffaut/Monocle/issues/215 就像 Monocle 一样,它无法更新 OptionNone。也许我需要换个角度思考这个问题?

谢谢

我不确定你为什么使用 Option[List[KeySet]]None 和空 List 之间有重要区别吗?

无论如何,我发现 fold 在使用选项时是一个方便的工具。

def updateUser(u :User, ks :KeySet) :User = {
  u.copy(settings =
    Some(u.settings.fold(Settings(Some(ks::Nil))) (stngs =>
      stngs.copy(keys = Some(stngs.keys.fold(ks::Nil) (ks::_))))))
}

val pat = updateUser(User(None), KeySet("a","b"))
//pat: User = User(Some(Settings(Some(List(KeySet(a,b))))))

val upat = updateUser(pat, KeySet("c","d"))
//upat: User = User(Some(Settings(Some(List(KeySet(c,d), KeySet(a,b))))))