【问题标题】:Filter defined fields of Options in scala在scala中过滤选项的定义字段
【发布时间】:2018-07-18 08:12:52
【问题描述】:

我有一个带有选项的案例类:

case class PersonUpdate(name: Option[String], age: Option[Int], country: Option[String])

我需要检查定义了哪些值并生成一个包含其名称和值的映射,例如:

如果我有这个对象:

val perUpdate = PersonUpdate(Option("john"), None, Option("England"))

地图应该是这样的:

val result = Map("people.$.name" -> "john", "people.$.country" -> "England")

以 scala 方式有效地做到这一点的最佳方法是什么?

【问题讨论】:

  • 如果您要寻求最佳实践,您真的应该使用Some("john") 而不是Option("john")Option 应该是 Some(x)None
  • stackoverflow.com/questions/1226555/case-class-to-map-in-scala 查看如何将案例类转换为地图的答案。
  • @VolodymyrGlushak 在这个链接中它只接受定义的字段..

标签: scala


【解决方案1】:

对于您的具体情况,您可以这样做:

List(
  perUpdate.name.map("people.$.name" -> _),
  perUpdate.age.map("people.$.age" -> _.toString),
  perUpdate.country.map("people.$.country" -> _)
).flatten.toMap

你可以有一个更通用的解决方案,但它不会特别有效:

perUpdate.getClass.getDeclaredFields.flatMap { f =>
  f.setAccessible(true)

  f.get(perUpdate).asInstanceOf[Option[Any]].map("people.$."+f.getName -> _.toString)
}.toMap

要仅提取某些字段,请尝试以下操作:

val fieldNames = List("name", "age", "country")

fieldNames.flatMap{ fieldName =>
  val fieldValue = perUpdate.getClass.getDeclaredField(fieldName)
  fieldValue.setAccessible(true)

  fieldValue.get(perUpdate).asInstanceOf[Option[Any]].map("people.$."+fieldName -> _.toString)
}.toMap

【讨论】:

  • 为什么匿名投反对票?请解释为什么这是一个不好的答案,以便我们都能学到一些东西。
  • 这是我的报复;) 当有一个不使用它的解决方案时,反射总是一个糟糕的答案。我不想早点投反对票(这是一个不错的解决方案,只是不是一个很好的解决方案),但是在您之前对我更好的答案表现出敌意之后,我改变了主意。
  • @Dima 你反对反思什么?在这种情况下似乎是一个有效的选项。
  • 普遍的反对意见是它像蜗牛一样慢。它还破坏了 api 合约,并失去了类型安全性。基本上,它完全违背了在 scala 中编写代码的全部目的。也可以只使用 javascript(其中地图和“案例类”已经是同一个东西 - 问题解决了)。
【解决方案2】:

案例类是Product 的实例,可以让您在不进行反射的情况下遍历其成员:

Seq("name", "age", "country")
  .map { "people.$." + _ }
  .iterator
  .zip(perUpdate.productIterator)
  .collect { case (k, Some(v)) => k -> v }
  .toMap

【讨论】:

  • 现在编译。很抱歉造成混淆 - 我只是想作为一个插图,没有费心去解决细节。
  • 这仍然没有产生正确的输出,第三次幸运?此外,这个解决方案是不稳定的,因为它依赖于程序员将字段名称的Seq 与案例类(名称、编号和顺序)保持同步。在具有多个程序员的大型系统中,这很难实现,如果你弄错了,编译器和运行时将无法帮助你。如果您关心健壮性和性能,则最好使用显式提取,如果您关心通用性,则最好使用反射。
  • 现在修复了输出(再次声明,提供完整的工作解决方案从来不是我的目标 - 只是方法的说明)。我认为,无论采用哪种方法,将案例类转换为地图都不是一个好主意,尤其是在“具有多个程序员的大型系统”中。
猜你喜欢
  • 2019-09-09
  • 2012-05-26
  • 1970-01-01
  • 2018-03-31
  • 1970-01-01
  • 2019-04-09
  • 2021-08-05
  • 2018-09-08
  • 1970-01-01
相关资源
最近更新 更多