Extending an object with a trait which needs implicit member

拥有回忆 提交于 2021-01-29 06:17:51

问题


I'm trying to have a code like below:

object MetaData extends CacheParams{}

So, since CacheParams needs implicit val p:Parameters, I tried:

object MetaData (implicit val p: Parameters) extends CacheParams

But it seems that I can't pass arguments to an object.

( because it gives error:traits or objects may not have parameters)

And if I don't pass any arguments it will give compile error that:

[error]: object creation impossible, since value p in trait CacheParams of type Parameters is not defined

I have no idea how to make this works. There were a few similar questions, but none of their answers solved my problem. Any help would be really appreciated. Thanks a lot.


回答1:


If I guessed the definition of CacheParams correctly

trait Parameters

trait CacheParams {
  implicit val p: Parameters
}

then you should: (1) replace the object

object MetaData /*(implicit val p: Parameters)*/ extends CacheParams

//object creation impossible. Missing implementation for:
//  implicit val p: Parameters // inherited from trait CacheParams

with a class

class MetaData(implicit val p: Parameters) extends CacheParams

or (2) implement the implicit inside the object

object MetaData extends CacheParams {
  override implicit val p: Parameters = new Parameters {}
}

or

implicit val params: Parameters = new Parameters {} // suppose an implicit is in current scope

object MetaData extends CacheParams {
  override implicit val p: Parameters = {
    val p = ??? // hiding above p to avoid ambiguous implicits, null or NPE, see (*) below
    implicitly[Parameters]
  }
}

(*) NullPointerException on implicit resolution

In (1) you're defining/resolving implicit now in current scope. In (2) you postpone resolving implicit till instantiating the class (resolving implicit in the scope of class constructor call site).

See also Pass implicit parameter through multiply objects

Yeah that would solve my problem. But I wanted to keep the object's body clean and decoupled from the configuration in Parameters, like the classes' bodies that accept the p: Parameters.

If in (1) you want to decouple the object from "the configuration in Parameters" you can try to introduce a trait (ParamsMaterializer):

object MetaData extends CacheParams with ParamsMaterializer

trait ParamsMaterializer {
  implicit val p: Parameters = new Parameters {}
}

or

implicit val params: Parameters = new Parameters {} // suppose an implicit is in current scope

object MetaData extends CacheParams with ParamsMaterializer

trait ParamsMaterializer {
  implicit val p: Parameters = {
    val p = ???
    implicitly[Parameters]
  }
}


来源:https://stackoverflow.com/questions/64286575/extending-an-object-with-a-trait-which-needs-implicit-member

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!