1

我已经看到了更新 a的官方示例Map,但我在语法上遇到了问题。

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 的一位作者的这个答案并没有编译。

4

2 回答 2

3

如果没有 Event 类的定义,我没有确切的答案,但是按照教程和大学示例,我可以使用撰写本文时的最新版本 monocle 1.5.0-cats-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 返回类型相对应。

于 2017-12-14T01:03:15.113 回答
0

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

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

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

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

labels composeOptional index("app")产量Optional[Metadata, String]。这显然行不通Map[String, String]:它间接从Metadatato Map[String, String](via labels) 然后立即从Map[String, String]to 它的String元素 (via 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"
)
于 2017-12-14T09:05:18.267 回答