如何在 Scala 中分解充满选项的案例类
我对 Scala 很陌生,我仍在努力适应语法和风格,所以这可能是一个非常简单的问题。
我正在使用一个代码库,其中有很多用选项填充的案例类,如下所示:
case class Person(
pants: Option[Pants]
)
case class Pants(
pocket: Option[Pocket]
)
case class Pocket(
cash: Option[Cash]
)
case class Cash(
value: String = "zilch"
)
在上面的示例中,您将如何返回 Person
的 中有多少钱裤子
口袋
,如果他们确实穿着有口袋的裤子,并且他们是否有钱?
I'm very new to Scala and I'm still trying to get used to the syntax and style, so this is probably a very simple question.
I'm working with a codebase where there are lots of case classes populated with Options like so:
case class Person(
pants: Option[Pants]
)
case class Pants(
pocket: Option[Pocket]
)
case class Pocket(
cash: Option[Cash]
)
case class Cash(
value: String = "zilch"
)
In the example above, how would you go about returning how much money is in a Person
's Pants
Pocket
, if they are indeed wearing pants... with pockets, and if they have any money at all?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
Scalaz 7 发生了一些变化,这是另一个示例:
Scalaz 7 has changed a little so here is another example:
这是 for-compressiveions 的好时机:
同样,你可以写以下,其中第一个代码是语法糖(忽略一些微妙之处):(
我不完全确定您是否可以像我一样使用
_
通配符编写最后一个表达式)。A great time for for-comprehensions:
Equivalently you can write the following, for which the first code is syntactic sugar (ignoring some subtleties):
(I'm not totally sure if you can write the last expression using the
_
wildcards, as I did).这个问题没有提到修改数据,但是当您需要这样做时,您很快就会发现 Scala 库没有工具可以让这变得简单(当数据不可变时)。如果您还没有经历过这种情况,请尝试编写一个函数来替换或修改
Person
持有的Cash
的value
,使用问题中定义的类型。正如 Tony Morris 的Scala 中的非对称透镜中所述,透镜是一种合适的这个问题的解决方案。
以下是我们如何使用
Lens
和PLens
访问和更新个人Cash
的value
的示例(部分镜头)来自 Scalaz 的 scalaz-7 分支的实现。首先,一些样板文件:为案例类的每个字段定义 Lens 实例。
A @-@ B
与Lens[A, B]
含义相同。但是,我们无法组合所有这些镜头,因为大多数字段都包含在
Option
类型中。部分透镜来救援:它们允许我们访问和更新可能不存在的结构部分,例如某个结构的
Some
值Option
,或List
的head
。我们可以使用 Scalaz 7 中的
somePLens
函数来创建查看每个可选字段的部分镜头。然而,为了用我们的常规镜头之一组成部分镜头,我们需要使用每个Lens< 上存在的
partial
方法来访问常规镜头的等效部分镜头实例。 /代码>。以同样的方式,我们可以通过组合所有镜头的
partial
实例,并将somePLens< 的实例夹在中间,来创建查看
Person
持有现金的部分镜头。 /代码>。在这里,我使用了<=<
运算符,它是andThen
的别名(相当于切换了操作数的compose
) 。创建一个
Person
实例来玩:使用部分镜头访问我拥有的现金价值:
使用部分镜头修改价值:
现在,如果我不 穿着任何裤子(!),我们可以看到修改我的现金价值的尝试将不会有任何效果:
The question didn't mention modifying the data, but when you need to do this you quickly find the Scala library doesn't have the tools to make this easy (when the data is immutable). If you haven't experienced this yet, try writing a function which will replace, or modify, the
value
of theCash
held by aPerson
, using the types defined in the question.As described in Tony Morris' Asymmetric Lenses in Scala, lenses are an appropriate solution to this problem.
Here's an example of how we can access and update the
value
of a person'sCash
using theLens
andPLens
(partial lens) implementations from the scalaz-seven branch of Scalaz.First, some boilerplate: define the Lens instance for each field of the case classes.
A @-@ B
means the same asLens[A, B]
.We can't compose all of these lenses, however, because most of the fields are wrapped in
Option
types.Partial Lenses to the rescue: these allow us to access and update parts of a structure that may not exist, such as the
Some
value of anOption
, or thehead
of aList
.We can use the
somePLens
function from Scalaz 7 to create a partial lens viewing each optional field. In order to compose a partial lens with one of our regular lenses, however, we need to access the equivalent partial lens instance for the regular lens, using thepartial
method that exists on everyLens
.In the same way, we can create our partial lens viewing the cash held by a
Person
by composing all our lenses'partial
instances, and sandwiching instances ofsomePLens
. Here, I've used the<=<
operator, an alias forandThen
(which is equivalent tocompose
with the operands switched).Creating a
Person
instance to play with:Using the partial lens to access the value of cash I have:
Using the partial lens to modify the value:
Now, if I'm not wearing any pants (!), we can see how an attempt to modify the value of my cash will have no effect:
ziggystar的答案是我会使用的,但为了完整性,也可以使用模式匹配,例如,
ziggystar's answer is what I would use, but for completeness, pattern matching can also be used, eg,