如何使用 Scala Guice 绑定 class 扩展具有 monadic 类型参数的 Trait?
How to bind a class that extends a Trait with a monadic type parameter using Scala Guice?
我需要绑定这个特性的实现:
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
:
中做类似的事情
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] ^
解决此问题的正确方法是什么?
我使用 Guice 的TypeLiteral, after reading this SO answer and this one找到了正确的解决方案。
有效的解决方案是:
// In Module.scala configure()
bind(new TypeLiteral[ClientRepository[IO]] {}).to(classOf[ClientRepositoryImpl])
因为我们必须提供一个可以实例化的class(带有类型参数,在我们的例子中是IO
)。 TypeLiteral
,这是一个特殊的 class,使您能够指定完整的参数化类型,可用于创建到我们 Repo[F[_]]
的特定实现的实际绑定。无法实例化具有泛型参数的 class,但我们可以强制 Guice 选择使用类型参数 cats.effect.IO
.
构造的特定 ClientRepository
最后但并非最不重要的一点是,每当您必须注入特征 ClientRepository
时,您还必须指定类型参数。例如:
class ClientResourceHandler @Inject()(
routerProvider: Provider[ClientRouter],
clientRepository: ClientRepository[IO]
)
ClientResourceHandler
需要调用 repo,所以我们使用特征 ClientRepository[IO]
注入它(不仅仅是 ClientRepository
)。
我需要绑定这个特性的实现:
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
:
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] ^
解决此问题的正确方法是什么?
我使用 Guice 的TypeLiteral, after reading this SO answer and this one找到了正确的解决方案。
有效的解决方案是:
// In Module.scala configure()
bind(new TypeLiteral[ClientRepository[IO]] {}).to(classOf[ClientRepositoryImpl])
因为我们必须提供一个可以实例化的class(带有类型参数,在我们的例子中是IO
)。 TypeLiteral
,这是一个特殊的 class,使您能够指定完整的参数化类型,可用于创建到我们 Repo[F[_]]
的特定实现的实际绑定。无法实例化具有泛型参数的 class,但我们可以强制 Guice 选择使用类型参数 cats.effect.IO
.
ClientRepository
最后但并非最不重要的一点是,每当您必须注入特征 ClientRepository
时,您还必须指定类型参数。例如:
class ClientResourceHandler @Inject()(
routerProvider: Provider[ClientRouter],
clientRepository: ClientRepository[IO]
)
ClientResourceHandler
需要调用 repo,所以我们使用特征 ClientRepository[IO]
注入它(不仅仅是 ClientRepository
)。