我正在尝试实现一个模拟IT网络和实例(计算机)的不可变数据结构。这是一个简化版本:
object Sample {
case class Instance(id: String, flag: Boolean)
case class Network(id: String, instances: Set[Instance])
case class Repo(networks: Map[String, Set[Network]])
// return new Repo with the instance with id == instanceId updated
// how to do this using lenses?
def updateInstanceFlag(networksKey: String, instanceId: String, flag: Boolean): Repo = ???
}
updateInstanceFlag函数应该创建一个更新的数据副本,并修改相应的实例(带有id instanceId)。我尝试使用镜头实现这一点,但代码太复杂了。 具体来说,我很难通过ID来更新数据结构来构建实例或网络的定位。从查询中返回可选值也会导致镜头的复杂性。 我使用了我自己的镜头实现,但没有真正的偏好(我知道从Shapeless,Monocle,Scalaz实现镜头)。
我很欣赏人们关于如何维护“真正的”不可变数据的想法和经验。
感谢。
答案 0 :(得分:3)
如果我可以说服您将instances
的{{1}}字段更改为Network
,那么您可以合理地完成此操作:
Map
由于代码如何下降和重新出现的对称性可能已经很明显,因此可能值得在可以更新单个网络上的实例标志的方法中考虑某些部分:
object Sample {
case class Instance(id: String, flag: Boolean)
case class Network(id: String, instances: Map[String, Instance])
case class Repo(networks: Map[String, Set[Network]])
// return new Repo with the instance with id == instanceId updated
// how to do this using lenses?
def updateInstanceFlag(repo: Repo, networksKey: String,
instanceId: String, flag: Boolean): Repo = {
val nets0 = repo.networks
val net0 = nets0(networksKey) // TODO fail gracefully
val inst0 = net0.instances(instanceId) // TODO fail gracefully
val inst1 = inst0.copy(flag = flag)
val net1 = net0 + (instanceId -> inst1)
val nets1 = nets0 + (networksKey -> net1)
repo.copy(networks = nets1)
}
}