scala:覆盖构造函数的隐式参数

时间:2011-05-11 09:36:03

标签: scala

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

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()以外的方法。

3 个答案:

答案 0 :(得分:8)

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

//  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
  }
}

这也使代码更加自我记录,因为很明显两个暗示是同一个。

答案 1 :(得分:3)

如果你希望周围有数以万计的implicits不相互冲突,你可以创建一个包装类,你可以用标记特征标记隐式用法。您可以使用各种语法;这是一个例子:

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

由于你必须使用包装器对象,它不是超级高效的,但它可以非常有效。 (或者非常令人困惑,因为隐含地发生了多少。)

答案 2 :(得分:0)

此修改编译。我把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()
  }
}