scala:重写构造函数的隐式参数

发布于 2024-11-06 13:37:58 字数 664 浏览 0 评论 0原文

我有一个类,它采用隐式参数,该参数由类内部方法调用的函数使用。我希望能够覆盖该隐式参数,或者从其源复制隐式参数。举个例子:

def someMethod()(implicit p: List[Int]) {
  // uses p
}

class A()(implicit x: List[Int]) {

  implicit val other = List(3) // doesn't compile

  def go() { // don't want to put implicit inside here since subclasses that override go() have to duplicate that
    someMethod()
  }
}

我想要的行为是 someMethod() 获取一个隐式参数,该参数是 x 的某些更改版本,这是该类的隐式参数。我希望能够在不更改 x 的情况下将其传递给 A 的构造函数,或者将其重写为我选择的新值。这两种方法似乎都不起作用。也就是说,在前一种情况下它不会复制列表,并且编译器会为后一种情况找到一个不明确的隐式值。有办法做到这一点吗?

我意识到我可以重新定义 go() 中的隐式值,但在我的情况下这不是一个好的选择,因为这个类被子类化了很多次,而且我只想在基类中处理这种隐式更改。所以它不一定需要在构造函数中,但必须在除 go() 以外的方法中。

I have a class that takes an implicit parameter which is used by functions called inside class methods. I want to be able to either override that implicit parameter, or alternatively, have the implicit argument be copied from its source. As an example:

def someMethod()(implicit p: List[Int]) {
  // uses p
}

class A()(implicit x: List[Int]) {

  implicit val other = List(3) // doesn't compile

  def go() { // don't want to put implicit inside here since subclasses that override go() have to duplicate that
    someMethod()
  }
}

The behavior I want is that someMethod() gets an implicit parameter that is some changed version of x, which was the class's implicit parameter. I want to be able to either mutate x without changing it for whatever passed it into A's constructor, or otherwise override it to a new value of my choosing. Both approaches don't seem to work. That is, it doesn't copy the list in the former case, and the compiler finds an ambiguous implicit value for the latter case. Is there a way to do this?

I realize that I can redefine the implicit value within go(), but this is not a good choice in my case because this class is subclassed numerous times, and I'd like to handle this implicit change in the base class only. So it doesn't necessarily need to go in the constructor, but it must be in a method other than go().

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

第七度阳光i 2024-11-13 13:37:58

引入另一种包装器类型,只是为了消除歧义:

//  badly named, choose something domain-specific
case class ListHolder(theList: List[Int])

def someMethod()(implicit holder: ListHolder) {
  val xs = holder.theList
  // uses xs ...
}

class A()(implicit xs: List[Int]) {

  implicit val other = ListHolder(42 :: xs) // compiles

  def go() {
    // xs is never considered for the implicit param to someMethod()
    // because it's now the wrong type
  }
}

这也使代码更加自文档化,因为两个隐式明显不同。

Introduce another wrapper type, simply to disambiguate:

//  badly named, choose something domain-specific
case class ListHolder(theList: List[Int])

def someMethod()(implicit holder: ListHolder) {
  val xs = holder.theList
  // uses xs ...
}

class A()(implicit xs: List[Int]) {

  implicit val other = ListHolder(42 :: xs) // compiles

  def go() {
    // xs is never considered for the implicit param to someMethod()
    // because it's now the wrong type
  }
}

This also makes the code more self-documenting, as it becomes blindingly obvious that the two implicits are not one and the same.

执笏见 2024-11-13 13:37:58

如果您希望有无数个隐式浮动并且不会相互冲突,您可以创建一个包装类,您可以使用标记特征来标记该包装类以供隐式使用。您可以使用多种语法;这是一个例子:

object Example {
  class Implication[A,B](val value: A) {
    def apply[C](c: C) = new Implication[C,B](c)
  }
  object Implication {
    def mark[B] = new Implication[Unit,B](())
    implicit def implication_to_value[A,B](i: Implication[A,B]) = i.value
  }

  trait One {}
  trait Two {}
  implicit val x = Implication.mark[One]("Hello")
  implicit val y = Implication.mark[Two]("Hi")

  def testOne(implicit s: Implication[String,One]) = println(s: String)
  def testTwo(implicit s: Implication[String,Two]) = println(s: String)
  def testThree(s: String) = println("String is " + s)

  def main(args: Array[String]) {
    testOne
    testTwo
    testThree(x)
    testThree(y)
  }
}

它如您所希望的那样工作:

scala> Example.main(Array())
Hello
Hi
String is Hello
String is Hi

由于您必须使用包装器对象,所以它不是超级高效,但它可以非常有效。 (或者非常令人困惑,考虑到有多少隐式发生的事情。)

If you want to have zillions of implicits floating around that don't collide with each other, you can create a wrapper class that you can tag with marker traits for implicit usage. There are a variety of syntaxes you could use; here's one example:

object Example {
  class Implication[A,B](val value: A) {
    def apply[C](c: C) = new Implication[C,B](c)
  }
  object Implication {
    def mark[B] = new Implication[Unit,B](())
    implicit def implication_to_value[A,B](i: Implication[A,B]) = i.value
  }

  trait One {}
  trait Two {}
  implicit val x = Implication.mark[One]("Hello")
  implicit val y = Implication.mark[Two]("Hi")

  def testOne(implicit s: Implication[String,One]) = println(s: String)
  def testTwo(implicit s: Implication[String,Two]) = println(s: String)
  def testThree(s: String) = println("String is " + s)

  def main(args: Array[String]) {
    testOne
    testTwo
    testThree(x)
    testThree(y)
  }
}

Which works as you would hope:

scala> Example.main(Array())
Hello
Hi
String is Hello
String is Hi

Since you have to use a wrapper object, it's not super-efficient, but it can be very effective. (Or very confusing, given how much happens implicitly.)

空气里的味道 2024-11-13 13:37:58

此修改可以编译。我将 x 更改为 var:

class A()(implicit var x: List[Int]) {

  def someMethod()(implicit p: List[Int]) {
    // uses p
  }

  x = List(3) 

  def go() { // don't want to put implicit inside here since subclasses that override go() have to duplicate that
    someMethod()
  }
}

This modification compiles. I changed x into a var:

class A()(implicit var x: List[Int]) {

  def someMethod()(implicit p: List[Int]) {
    // uses p
  }

  x = List(3) 

  def go() { // don't want to put implicit inside here since subclasses that override go() have to duplicate that
    someMethod()
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文