【问题标题】:Correct syntax for updating nested map using Monocle使用 Monocle 更新嵌套地图的正确语法
【发布时间】:2017-12-14 17:10:50
【问题描述】:

我已经看到了更新 Mapofficial example,但我遇到了语法问题。

val pod: Lens[Event, Pod] = GenLens[Event](_.`object`)
val metadata: Lens[Pod, Metadata] = GenLens[Pod](_.metadata)
val labels: Lens[Metadata, Map[String, String]] = GenLens[Metadata](_.labels)

我想更新labels Map 中的关键“应用程序”。但我无法编译以下内容:

(labels.composeOptional(index("app"))).set("whatever")(someLabels)

事实上,Monacle 的作者之一的answer 无法编译。

【问题讨论】:

  • someLabels 到底是什么?合成镜头是从Metadata 到索引"app" 映射的labels 元素的间接映射,因此someLabels 应该是Metadata 类型。
  • @P.Frolov 这是Map[String,String]

标签: scala monocle-scala


【解决方案1】:

没有你的 Event 类的定义,我没有一个确切的答案,但是following the tutorial 和大学的例子,我可以用写这篇文章时的最新版本更新嵌套地图,单片眼镜 1.5.0-猫-M1。确保在您的项目中同时拥有 monocle-core 和 monocle-macros jar。那么,

import monocle.macros.GenLens
import monocle.function.At.at // // to get at Lens 
import monocle.std.map._      // to get Map instance for At

那么,以大学为例,

case class Lecturer(firstName: String, lastName: String, salary: Int)
case class Department(budget: Int, lecturers: List[Lecturer])
case class University(name: String, departments: Map[String, Department])

val departments = GenLens[University](_.departments) 

val uni = University("oxford", Map(
"Computer Science" -> Department(45, List(
  Lecturer("john"  , "doe", 10),
  Lecturer("robert", "johnson", 16)
)),
"History" -> Department(30, List(
  Lecturer("arnold", "stones", 20)
)))) 

我可以

(departments composeLens at("History")).set(Some(Department(30, List(Lecturer("arnold", "stones", 30)))))(uni)

与您上面的代码的主要区别在于使用 at() 以及使用 Some 包装 Department 以在使用键从 Map 中检索值时与 Option 返回类型相对应。

【讨论】:

  • 我选择了 quicklens,因为我的使用量很少,不值得涉足这些问题。 Monocle 还带来了很多依赖项(Scalaz、Shapeless),这对于我的目的来说又是多余的。我稍后会玩它,如果它对我有用,请接受你的回答。在此之前,请考虑点赞以表示感谢。
  • @AbhijitSarkar 只有单片眼镜通用模块依赖于我不认为你正在使用它的 shapeless。 Scalaz 或 cat 是 core 中唯一的依赖项,如果你想在 scala 中执行 fp,它是必需的。
【解决方案2】:

考虑到someLabels 的类型为Map[String, String],您的代码要么过多,要么只是为组合Optional 提供了错误的参数。如果我们在Lens[S, A] 中简化composeOptional 方法的签名,它会产生:

def composeOptional(other: Optional[A, B]): Optional[S, B]

Optional[A, B],在非常不精确的近似下,对应于允许:

  • 查看 A 类型的值并获取其类型为 B 的组件(或 A 本身,如果它缺失);
  • 通过替换 B 类型的组件来构建一个 A 类型的新对象(或者如果没有此类组件,则只返回原始对象)。

labels composeOptional index("app") 产生Optional[Metadata, String]。这显然不适用于Map[String, String]:它从Metadata 间接到Map[String, String](通过labels),然后立即从Map[String, String] 到它的String 元素(通过index("app")),隐藏地图访问完全来自用户。如果您想在someLabels 映射中的给定键处设置一个值,则使用index 就足够了:

val someLabels1 = Map("app" -> "any")
val someLabels2 = Map("unit" -> "any")
index("app").set("whatever")(someLabels1) // Map("app" -> "whatever")
index("app").set("whatever")(someLabels2) // Map("unit" -> "any")

另一方面,您编写的Optional 可以在Metadata 上工作:

case class Metadata(labels: Map[String, String])
val someLabels = Map("app" -> "any")
val meta = Metadata(someLabels)
(labels composeOptional index("app")).set("whatever")(meta) 
// Metadata(Map("app" -> "whatever")

我已经检查了以下版本(build.sbt):

scalaVersion := 2.12.3

libraryDependencies ++= Seq(
  "com.github.julien-truffaut" %% "monocle-core" % "1.4.0",
  "com.github.julien-truffaut" %% "monocle-macro" % "1.4.0"
)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-20
    • 1970-01-01
    • 2016-07-02
    • 1970-01-01
    • 1970-01-01
    • 2015-02-11
    相关资源
    最近更新 更多