折叠案例类别
我遇到的情况是,我有几个案例类,其中所有变量都是可选的。
假设我有:
case class Size(width: Option[Int], height: Option[Int])
case class Foo(a: Option[String], b: Option[Boolean], c: Option[Char])
给定相同类型案例类的集合,我想将它们折叠起来比较选项值并保留定义的值。即对于 Size
:
values.foldLeft(x) { (a, b) =>
Size(a.width.orElse(b.width), a.height.orElse(b.height))
}
我想以更通用的方式对任何像上面这样的案例类执行此操作。我正在考虑用 unapply(_).get
等做一些事情。有谁知道解决这个问题的聪明方法吗?
I have a situation where I have a couple of case classes where all of their variables are optional.
Let's say I have:
case class Size(width: Option[Int], height: Option[Int])
case class Foo(a: Option[String], b: Option[Boolean], c: Option[Char])
Given a collection of the same type of case class I would like to fold over them comparing the option values and keep the values which are defined. I.e. for Size
:
values.foldLeft(x) { (a, b) =>
Size(a.width.orElse(b.width), a.height.orElse(b.height))
}
I would like to do this in a more general way for any of the case classes like the ones above. I'm thinking about doing something with unapply(_).get
etc. Does anyone know a smart way to solve this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
好的,考虑一下:
可以重载
foldCase
以接受两个、三个或更多参数,每个参数都有一个版本的 f。然后它可以与任何案例类别一起使用。由于需要担心元组问题,因此下面是使其与案例类或两个参数一起使用的一种方法。将其扩展到更多参数就很简单了,尽管有点烦人。要重载使用它,只需将所有定义放入一个对象中:
但是,当您这样做时,您必须显式地将
apply
和unapply
转换为函数:它可能是可以将它变成结构类型,这样你只需要传递伴生对象,但我做不到。在#scala 上,我被告知答案是肯定的,至少对于我处理这个问题的方式来说是这样。
Ok, consider this:
One could overload
foldCase
to accept two, three, or more parameters, one version of f for each arity. It could then be used with any case class. Since there's the tuple-thing to worry about, below's one way to make it work with case classes or two parameters. Expanding it to more parameters is then trivial, though a bit tiresome.To use it overloaded, just put all definitions inside one object:
When you do this, however, you'll have to explicitly turn
apply
andunapply
into functions:It might be possible to turn it into a structural type, so that you only need to pass the companion object, but I couldn't do it. On #scala, I was told the answer is a definitive no, at least to how I approached the problem.
[代码更新]
这是一种解决方案,每个“arity”只需要一个抽象类:
请注意,当其他具有相同构造函数的案例类时,隐式
<:<
参数将给出编译时错误参数被传递给该方法。然而,需要一个“格式良好”的构造函数,否则反射代码将会崩溃。
[Code updated]
Here is an solution which requires only one abstract class per "arity":
Note that the implicit
<:<
argument will give a compile time error when other case classes with the same constructor arguments are passed to the method.However, a "well formed" constructor is required, else the reflection code will blow up.
您可以使用
productElement
或productIterator
(在 scala.Product) 来一般检索/迭代案例类(和元组)的元素,但它们的类型为 Any,所以会有一些痛苦。You can use
productElement
orproductIterator
(on scala.Product) to generically retrieve/iterate the elements of case classes (and tuples), but they're typed as Any, so there will be some pain.