scala - 如何使用 ZIO 配置处理 ADT(密封特征)
问题描述
如何使用ZIO Conf为代数数据类型手动添加配置描述。
在示例中,我找到了一个关于如何使用Magnolia处理ADT的示例。
手动添加配置描述时也可以这样做吗?
这里有一个例子:
sealed trait Dance
final case class A(any: Person) extends Dance
final case class B(body: Height) extends Dance
final case class Person(name: String, age: Option[Int])
final case class Height(height: Long)
与木兰:
val danceConfig = description[Dance]
手动:
val danceConfig = ???
解决方案
正如您所期望的那样,它很冗长。但是有不同的方法可以做到这一点,这是一个偏好问题。
我们试图在这两个选项中比要求的更详细一些,以便更好地理解
选项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 中。非常感谢这个问题,希望答案对您有所帮助。
推荐阅读
- c++ - 离开类文件时变量重置
- python - 月份范围计算未返回预期结果
- xamarin.forms - Xamarin 表单:如何连接蓝牙打印机并打印收据
- javascript - 如何允许用户使用 php html css js 在 wyswg 中自定义电子商务商店主题
- c# - 如何在.net core中为多个区域定义路由
- php - 如何将 Codeigniter 方法的返回整数作为整个控制器的全局变量?
- apache-kafka-connect - 升级单个连接器是否需要重新启动工作器?
- git - git 的 --pretty 选项字符串格式的别名
- mysql - 具有意外结果的棘手 JOIN 问题
- laravel - 我应该在 Laravel 路由中使用哪种 http 请求方法?