如何使用Scala Guice绑定带有Monadic类型参数的扩展Trait的类? [英] How to bind a class that extends a Trait with a monadic type parameter using Scala Guice?

查看:125
本文介绍了如何使用Scala Guice绑定带有Monadic类型参数的扩展Trait的类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要绑定此特征的实现:

I need to bind the implementation of this trait:

trait ClientRepository[F[_]] {
  def list(): F[Iterable[ClientDTO]]
}

此实现:

import cats.effect.IO

@Singleton
class ClientRepositoryImpl @Inject()(db: OldDataBase, c: IOContextShift)
    extends ClientRepository[IO] {

  override def list(): IO[Iterable[ClientDTO]] = ???
}

我正在使用Scala Play! v2.7.2和Scala v2.12.8,以及scala-guice v4.2.1.为了将特征绑定到其实现,我想在我的Module.scala:

I'm using Scala Play! v2.7.2 and Scala v2.12.8, with scala-guice v4.2.1. In order to bind the trait to its implementation I would like to do something like that in my Module.scala:

class Module(environment: Environment, configuration: Configuration)
    extends AbstractModule
    with ScalaModule {

  override def configure() = {

    bind[ClientRepository].to[ClientRepositoryImpl[IO]].in[Singleton]

  }
}

我得到的错误是:

[error] app/Module.scala:37:9: kinds of the type arguments (ClientRepository) do not conform to the expected kinds of the type parameters (type T).
[error] ClientRepository's type parameters do not match type T's expected parameters:
[error] trait ClientRepository has one type parameter, but type T has none
[error]     bind[ClientRepository].to[ClientRepositoryImpl[IO]].in[Singleton]
[error]         ^
[error] app/Module.scala:37:31: ClientRepositoryImpl does not take type parameters
[error]     bind[ClientRepository].to[ClientRepositoryImpl[IO]].in[Singleton]
[error]                               ^
[error]

我也尝试过:

bind[ClientRepository[IO]].to[ClientRepositoryImpl].in[Singleton]

Module.scala:37:9: kinds of the type arguments (cats.effect.IO) do not conform to the expected kinds of the type parameters (type T).
[error] cats.effect.IO's type parameters do not match type T's expected parameters:
[error] class IO has one type parameter, but type T has none
[error]     bind[ClientRepository[IO]].to[ClientRepositoryImpl].in[Singleton]
[error]         ^

bind[ClientRepository[IO[_]]].to[ClientRepositoryImpl].in[Singleton]

Module.scala:37:27: cats.effect.IO[_] takes no type parameters, expected: one
[error]     bind[ClientRepository[IO[_]]].to[ClientRepositoryImpl].in[Singleton]
[error]                           ^

解决此问题的正确方法是什么?

What's the correct way to fix this?

推荐答案

我使用Guice的 TypeLiteral 找到了正确的解决方案,在阅读此SO答案这个.

I found the proper solution using Guice's TypeLiteral, after reading this SO answer and this one.

有效的解决方案是:

    // In Module.scala configure()
    bind(new TypeLiteral[ClientRepository[IO]] {}).to(classOf[ClientRepositoryImpl])

因为我们必须提供一个可以实例化的类(带有类型参数,在我们的例子中是IO). TypeLiteral是一个特殊类,可让您指定完整的参数化类型,可用于创建与Repo[F[_]]特定实现的实际绑定.具有泛型参数的类无法实例化,但是我们可以强制Guice选择使用类型参数cats.effect.IO构造的特定ClientRepository.

because we must provide a class that can be instantiated (with a type parameter, that in our case is IO). TypeLiteral, which is a special class that enables you to specify a full parameterized type, can be used to create the actual binding to a particular implementation of our Repo[F[_]]. A class with a generic parameter cannot be instantiated but we can force Guice to pick up a specific ClientRepository that has been constructed with the type parameter cats.effect.IO.

最后但并非最不重要的一点是,每当必须注入特征ClientRepository时,也必须指定type参数.例如:

Last but not least whenever you have to inject the trait ClientRepository you have to specify the type parameter as well. For instance:

class ClientResourceHandler @Inject()(
    routerProvider: Provider[ClientRouter],
    clientRepository: ClientRepository[IO]
)

ClientResourceHandler需要调用该仓库,因此我们使用特征ClientRepository[IO](而不仅仅是ClientRepository)注入它.

the ClientResourceHandler needs to call the repo, so we're injecting it using the trait ClientRepository[IO] (not just ClientRepository).

这篇关于如何使用Scala Guice绑定带有Monadic类型参数的扩展Trait的类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆