当后者具有隐式参数时,如何正确地将特征绑定到其 impl

Posted

技术标签:

【中文标题】当后者具有隐式参数时,如何正确地将特征绑定到其 impl【英文标题】:How to properly bind a trait to its impl when the later one has implicit parameters 【发布时间】:2017-07-16 20:56:12 【问题描述】:

[请原谅我问了这么长的问题,我还在学习 Scala。]

我正在尝试将通用特征绑定到具有隐式参数的通用 impl。这是清理代码:

trait PersistenceService[T <: SomeOtherClass]  
  def persist(record: T): Future[Unit]


class MongoPersistenceService[T <: SomeOtherClass] @Inject()(implicit ec: ExecutionContext, tag: ClassTag[T]) extends PersistenceService[T] 
  val collectionName: String = tag.runtimeClass.getSimpleName
  val databaseName = "someDatabase"

  def db: Future[DefaultDB] = MongoConnectionWrapper.getMongoConnection("mongodb://127.0.0.1", "27017")
                              .flatMap(_.database(databaseName))

  def collection: Future[BSONCollection] = db.map(_.collection(collectionName))

  def persist(record: T): Future[Unit] = 
    val result = for 
      col <- collection
      writeResult <- col.insert(record)
     yield writeResult
    result.recoverWith 
                         case WriteResult.Code(11000) => throw RecordAlreadyExistsException(record,
                                                                                            "")
                       .map(_ => ())
  

  def read(id: BSONObjectID): Future[T] = 
    val query = BSONDocument("_id" -> id)
    val readResult: Future[T] = for 
      coll <- collection
      record <- coll.find(query).requireOne[T]
     yield record

    readResult.recoverWith 
                             case NoSuchResultException => throw RecordNotFoundException(id)
                           
  

我正在使用 Play、ReactiveMongo 和 ScalaGuice(所有最新版本)。所以这是我绑定一切的主要模块类:

class Module(env: Environment, config: Configuration) extends AbstractModule with ScalaModule 
  def configure(): Unit = 
    bind[PersistenceService[_]].to[MongoPersistenceService[_]] // Also tried with specific class instead of _ but not working either
  

假设我有一个依赖于 PersistenceService 的控制器,如下所示:

class PersistenceServiceController @Inject()(val PersistenceService: PersistenceService[Bar], cc ControllerComponents) extends AbstractController(cc)  ... 

以及模型(您可能已经猜到)及其隐含的 Reader/Writer:

case class Bar() extends SomeOtherClass() 
object Bar 
  implicit object BarReader extends BSONDocumentReader[Bar] 
    def read(doc: BSONDocument): Bar =  ... 
  
  implicit object BarWriter extends BSONDocumentWriter[Bar] 
    def write(bar: Bar): BSONDocument =  ... 
  

有了所有这些东西,我得到了以下运行时异常:

com.google.inject.CreationException: Unable to create injector, see the following errors:
1) No implementation for reactivemongo.bson.BSONDocumentReader<Bar> was bound.
  while locating reactivemongo.bson.BSONDocumentReader<Bar>
    for the 2nd parameter of MongoPersistenceService.<init>(MongoPersistenceService.scala:15)
  at Module.configure(Module.scala:14) (via modules: com.google.inject.util.Modules$OverrideModule -> Module)
2) No implementation for reactivemongo.bson.BSONDocumentWriter<Bar> was bound.
  while locating reactivemongo.bson.BSONDocumentWriter<Bar>
    for the 3rd parameter of persistence.MongoPersistenceService.<init>(MongoPersistenceService.scala:15)
  at Module.configure(Module.scala:14) (via modules: com.google.inject.util.Modules$OverrideModule -> Module)
3) No implementation for scala.reflect.ClassTag<Bar> was bound.
  while locating scala.reflect.ClassTag<Bar>
    for the 5th parameter of MongoPersistenceService.<init>(MongoPersistenceService.scala:15)
  at Module.configure(Module.scala:14) (via modules: com.google.inject.util.Modules$OverrideModule -> Module)

很明显,我的 MongoPersistenceService 类应该在执行上下文中获取的东西缺少一些方法。我知道当你用 guice 正确设置你的东西时,Play 会神奇地提供执行上下文。但在这种情况下,它似乎不起作用。

我该如何解决这个问题?

【问题讨论】:

【参考方案1】:

好吧,我对这个感觉很不好,但是错误消息很明显可以找到问题。为了解决这个问题,我必须手动绑定 BSONDocumentReader[Bar]BSONDocumentWriter[Bar]ClassTag[Bar] 的 impl。

我将我的代码重构为更简单的东西。 但想让其他人知道问题出在哪里。

【讨论】:

以上是关于当后者具有隐式参数时,如何正确地将特征绑定到其 impl的主要内容,如果未能解决你的问题,请参考以下文章

映射打字稿参数:绑定元素“列”隐式具有“任何”类型

如何正确地将 Popup 绑定到 ToggleButton?

正确地将可拖动元素恢复到其起始位置

Laravel 8:如何使隐式模型绑定路由参数可选而不是抛出 404?

如何修复绑定元素'children'隐式具有'any' type.ts(7031)?

如何在 Spark 中正确地将数字特征与文本(词袋)结合起来?