5

我正在尝试创建一个 ZIO 模块的示例,它有两种实现:

  1. 将 YAML 与 circe-yaml 一起使用
  2. 将 HOCON 与 pureConfig 一起使用

我的一般界面如下所示:

trait Service[R] {
  def load[T <: Component](ref: CompRef): RIO[R, T]
}

现在我的 YAML 实现看起来像:

def loadYaml[T <: Component: Decoder](ref: CompRef): RIO[Any, T] = {...}

Decoder是特定于实现的。

现在的问题是如何将服务实现委托给loadYaml.

我尝试了以下方法:

val components: Components.Service[Any] = new Components.Service[Any] {

  implicit val decodeComponent: Decoder[Component] =
      List[Decoder[Component]](
         Decoder[DbConnection].widen,
           ...
        ).reduceLeft(_ or _)

   def load[T <: Component](ref: CompRef): RIO[Any, T] = loadYaml[T] (ref)
}

这给了我:

Error:(62, 20) could not find implicit value for evidence parameter of type io.circe.Decoder[T]
       loadYaml[T] (ref)

有没有办法做到这一点?

我在 Github 上创建了一个示例项目:zio-comps-module

这里描述了这个想法:Decouple the Program from its Implementation with ZIO modules

4

2 回答 2

3

好的,我找到了解决方案。我所要做的就是调整load功能:

def load[T <: Component](ref: CompRef): RIO[ComponentsEnv, T] = {
  loadConf[Component](ref).map { case c: T => c }
}

首先loadConf是类型Component

第二次转换 result( Component) 结果类型T

这可行,但会给您带来难看的警告:

[warn] /Users/mpa/dev/Github/pme123/zio-comps-module/hocon/src/pme123/zio/comps/hocon/HoconComps.scala:37:46: abstract type pattern T is unchecked since it is eliminated by erasure
[warn]       loadConf[Component](ref).map { case c: T => c }
[warn]                                              ^
[warn] /Users/mpa/dev/Github/pme123/zio-comps-module/hocon/src/pme123/zio/comps/hocon/HoconComps.scala:37:36: match may not be exhaustive.
[warn] It would fail on the following inputs: DbConnection(_, _, _, _), DbLookup(_, _, _, _), MessageBundle(_, _)
[warn]       loadConf[Component](ref).map { case c: T => c }
[warn]                                    ^
[warn] two warnings found

更新 - 我找到了一个摆脱警告的解决方案:

在第十次阅读警告后unchecked since it is eliminated by erasure,我记得这可以通过添加ClassTagas Context Bound来解决。

该服务现在看起来

trait Service[R] {
  def load[T <: Component: ClassTag](ref: CompRef): RIO[R, T]
}
于 2019-12-08T09:10:12.527 回答
0

如果问题在于你的特质

def load[T <: Component]

在实现中你需要

def loadYaml[T <: Component: Decoder]

那么也许你只需要参数化Decoder

trait Service[R, D] {
  def load[T <: Component: D](ref: CompRef): RIO[R, T]
}

如果不同类型之间没有关系,D那么您可以将其定义为Any然后具有特征 be trait Service[R, +D]

于 2019-12-09T15:02:06.970 回答