我正在尝试在scala中组合一个类似DSL的函数集,而我想要的是......的效果......
implicit val x = 1
doSomething() // uses x
context { implicit y =>
doSomething() // uses y
doSomethingElse() // uses y
}
其中context
是......的效果。
def context[A](f: Int => A) = f(2)
我遇到的问题是,使用此语法,scala将报告ambiguous implicit values
。我有点假设,如果一个隐含的被定义在一个“更接近”的范围内,那么它将会越过更远的范围,但看起来并非如此。
有没有办法向scala发出信号,说明一个隐含的比另一个更具体(除了我认为更强的范围)?
答案 0 :(得分:3)
一种可能的解决方案是将内部参数命名为与外部参数相同。
context { implicit y =>
到
context { implicit x =>
这可行,但不太可取。有更好的解决方案吗?
答案 1 :(得分:1)
这可能不是你想要的,但它有点相关,所以它可能会给你一些想法。
您可以对隐式类进行子类型化,并利用将选择最具体类型的事实:
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
方法来获取类型A的隐式参数。我们必须在范围a
和b
中使用类型A的隐式val,但是{{1更具体,因此没有歧义,输出显示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()
}
方法(您的bar
)。
证明它有效的一个小例子:
context
这里有两种可能的问题:B 必须扩展A,如果忘记了,它会在两种情况下都打印“A”。如果您忘记在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
的调用中将implicit
关键字放在参数上,则类似。
您在这里获得的是能够在不同的A上调用bar
不同的A值而不明确指定它们。