正如你所预期的那样,它很啰嗦。但有不同的方法来做到这一点,这是一个偏好问题。
我们在这两个选项中都尝试更加冗长,以便更好地理解。
选项1:
val personConfig =
(string("name") |@| int("age").optional)(Person.apply, Person.unapply)
val heightConfig =
long("height").xmap(Height)(_.height)
val aConfig = nested("any")(personConfig).xmap(A)(_.any)
val bConfig = nested("body")(heightConfig).xmap(B)(_.body)
val cConfig = boolean("can").xmap(C)(_.can)
val dConfig = string("dance").xmap(D)(_.dance)
val danceConfig =
aConfig
.orElseEither(bConfig)
.orElseEither(cConfig)
.orElseEither(dConfig)
.xmap({
case Right(value) => value: Dance
case Left(value) =>
value match {
case Right(value) => value: Dance
case Left(value) =>
value match {
case Right(value) => value: Dance
case Left(value) => value: Dance
}
}
})({
case d @ D(_) => Right(d)
case c @ C(_) => Left(Right(c))
case b @ B(_) => Left(Left(Right(b)))
case a @ A(_) => Left(Left(Left(a)))
}
)
写入时有些复杂,但全部基于类型驱动。
选项2
val personConfig =
(string("name") |@| int("age").optional)(Person.apply, Person.unapply)
val heightConfig =
long("height").xmap(Height)(_.height)
val aConfig = nested("any")(personConfig).xmap(A)(_.any)
val bConfig = nested("body")(heightConfig).xmap(B)(_.body)
val cConfig = boolean("can").xmap(C)(_.can)
val dConfig = string("dance").xmap(D)(_.dance)
val aConfigAsDance =
aConfig.xmapEither(a => Right(a: Dance))({
case a: A => Right(a)
case _ => Left("unable to write back")
})
val bConfigAsDance =
bConfig.xmapEither(a => Right(a: Dance))({
case a: B => Right(a)
case _ => Left("unsable to write back")
})
val cConfigAsDance =
cConfig.xmapEither(a => Right(a: Dance))({
case a: C => Right(a)
case _ => Left("unsable to write back")
})
val dConigAsDance =
dConfig.xmapEither(a => Right(a: Dance))({
case a: D => Right(a)
case _ => Left("unsable to write back")
})
val danceConfig =
aConfigAsDance.orElse(bConfigAsDance).orElse(cConfigAsDance).orElse(dConigAsDance)
你会注意到,在写入部分(xmapEither的第二个参数)中,我们确保它是正确的类型。例如:在
aConfigAsDance
中,假设它只能是A并进行
asInstanceOf
是不安全的。
通过使用 xmapEither
,我们能够编写安全且纯净的代码,并且我们已经遵循了这种方式。
未来,ZIO-Config 将推出一些帮助函数来处理 Either。这是因为 ZIO-Config 的哲学是尽可能为用户提供尽可能少的神奇接口,而您仍然可以使用 zio-config-magnolia 将它们缩短为一行,即
val danceConfig = description[Dance]
如果您感兴趣,很高兴在zio-config中看到这个例子。非常感谢这个问题,希望答案有所帮助。