Это многословно, как и следовало ожидать. Но есть разные способы сделать это, и это вопрос предпочтения.
Мы постарались быть более многословными, чем требовалось в обоих этих вариантах, для лучшего понимания
Вариант 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, если вы заинтересованы. Большое спасибо за этот вопрос и надеюсь, что ответ будет полезным.