【问题标题】:How to handle an ADT (sealed trait) with ZIO config如何使用 ZIO 配置处理 ADT(密封特征)
【发布时间】:2020-04-27 10:27:54
【问题描述】:

如何使用ZIO Conf代数数据类型手动添加配置说明

examples 中,我找到了一个关于如何使用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 = ???

【问题讨论】:

    标签: scala zio zio-config


    【解决方案1】:

    正如您所期望的那样冗长。但是有不同的方法,这是一个偏好问题。

    我们试图在这两个选项中比要求的更详细一些,以便更好地理解

    选项 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 中。非常感谢这个问题,希望答案对您有所帮助。

    【讨论】:

      猜你喜欢
      • 2016-07-18
      • 2020-03-30
      • 2021-10-01
      • 1970-01-01
      • 2018-12-18
      • 2017-04-23
      • 1970-01-01
      • 2015-05-26
      相关资源
      最近更新 更多