Возможно, это не совсем то, что вы ищете, но это своего рода связанное, поэтому, возможно, это даст вам некоторые идеи.
Вы можете подтип класса неявных и воспользоваться тем фактом, что наиболее конкретным типа будет выбран:
scala> :paste
// Entering paste mode (ctrl-D to finish)
class A { override def toString = "A" }
class B extends A { override def toString = "B" }
implicit val a = new A
implicit val b = new B
def foo()(implicit x: A) { println(x) }
// Exiting paste mode, now interpreting.
defined class A
defined class B
a: A = A
b: B = B
foo:()(implicit x: A)Unit
scala> foo()
B
Здесь мы определили метод foo
принять неявный параметр типа А. Мы должны подразумевать vals типа A в области, a
и b
, но более конкретно, b
, и поэтому нет никакой двусмысленности, и на выходе показано, что выбрано b
.
Давайте попробуем адаптировать его к примеру:
class A
class B extends A
def foo()(implicit a: A) = a
def bar[U](p: B => U) { p(new B) }
implicit val a = new A
bar { implicit b =>
foo()
}
Хитрость здесь заключается в использовании подтипов класса в paremeter к bar
методу (ваш context
).
Немного расширенный пример, чтобы доказать, что он работает:
scala> :paste
// Entering paste mode (ctrl-D to finish)
class A {
override def toString = "A"
def getB = new B
}
class B extends A {
override def toString = "B"
}
def foo()(implicit a: A) { println(a) }
def bar[U](p: B => U)(implicit a: A) { p(a.getB) }
implicit val a = new A
def test() {
foo() // should print "A"
bar { implicit b =>
foo() // should print "B"
}
}
// Exiting paste mode, now interpreting.
defined class A
defined class B
foo:()(implicit a: A)Unit
bar: [U](p: B => U)(implicit a: A)Unit
a: A = A
test:()Unit
scala> test()
A
B
Есть два возможных подводных камней здесь: B должны удлинить, если вы забыли, что он будет печатать «А» в обоих случаях. И похоже, если вы забудете поставить ключевое слово implicit
по параметру в вызове bar
.
Что вы получили здесь, это возможность вызвать foo
в разных контекстах с разными значениями A без их явного указания.
Это действительно интересный трюк, и я думаю, что он решает точную проблему, которую я искал. Я дам это в моем случае использования и отметьте его как ответ, если он работает (и, похоже, это так). –