【问题标题】:Is there a way to implicitly convert an implicit parameter in Scala?有没有办法在 Scala 中隐式转换隐式参数?
【发布时间】:2011-03-05 15:59:25
【问题描述】:

有没有办法使这项工作(Scala 2.8.1):

class A
class B
def f(implicit b: B) {}
implicit val a = new A
implicit def aToB(a: A) = new B
f(a) // works ok
f // error: could not find implicit value for parameter b: B

实际上我的问题在于 Lift (2.2) 的依赖注入,我正在尝试将 Vendor[T] 转换为 T 并在类构造函数中隐式要求它,而不在每个 val 之后添加导入:

object DependencyFactory extends Factory {
  implicit def vendorToVal[T](vendor: Vendor[T]): T = vendor.vend

  implicit val db = new FactoryMaker[DbAccess](Model) {}
  //uncommenting the following line makes it work, but can we avoid it? 
  //import db._
  implicit val userStore = new FactoryMaker[UserStore](new UserStore) {}
}

UserStore 在哪里:

class UserStore(implicit db: DbAccess)

我做错了吗?

更新

感谢Easy Angel回答第一部分。但它并没有解决我的 Lift DI 问题,因为事实证明,范围内存在相反的转换(从 T 到 Vendor[T]),并且这两者都会导致“错误:发散隐式扩展”。

可以解决吗?

更新2

哇,在上一个问题之后又出现了一个问题:从某个 Container[T] 到 T 的转换在范围内具有 Container[U] 的隐式实例,并且一个具有隐式参数 U 的函数也会导致“发散隐式扩展”:

class A
case class Vendor[T](v: T)
def f(implicit a: A) {}
implicit val vendor = Vendor(new A)
implicit def vendorToVal[T](implicit v: Vendor[T]) = v.v
f

有什么提示吗?

【问题讨论】:

  • 关于 Update2... 我尝试使用 -Xlog-implicits 选项运行编译器,在我看来,编译器无法正确推断 T。例如,如果你写implicit def vendorToVal(implicit v: Vendor[A]): A = v.v,它将编译。但我仍然不确定......我也很高兴知道它无法编译的原因。我认为这本身就值得质疑。所以我建议你用Update2创建新问题。

标签: scala dependency-injection lift implicit-conversion


【解决方案1】:

你几乎成功了。你只需要声明a隐式:

implicit def aToB(implicit a: A) = new B

在这种情况下,编译器尝试为f 的第一个隐式参数找到一些隐式B,并找到aToB。比编译器联系以满足aToB 的要求(implicit a: A)并找到您的implicit val a

【讨论】:

  • 谢谢,它适用于我的简单示例,但在 Lift 的情况下会导致“发散隐式扩展”。让我们看看那里有什么可以做的......
【解决方案2】:

这可能不是解决此问题的最佳和最简洁的解决方案。但对我来说,从技术上讲是否可以实现您想要的东西对我来说很有趣。我试图在没有 Lift 的情况下尽可能接近地重现所有涉及的类......这是使用视图边界的可能解决方案之一:

class DbAccess
class UserStore[T](implicit db: T, ev: T => DbAccess)

class Vendor[T] (val vend: T)
class FactoryMaker[T] (vend: T) extends Vendor[T](vend)

implicit def vendorToVal[T](vendor: Vendor[T]) = vendor.vend

implicit val db: Vendor[DbAccess] = new FactoryMaker[DbAccess](new DbAccess) {}
implicit val userStore = new FactoryMaker[UserStore[Vendor[DbAccess]]](new UserStore) {}

在这种情况下,UserStore 知道T 不是DbAccess,但它也知道T 可以作为T 被查看和使用。


编辑

关于您的第二个示例(在评论中)。我想到了这个简单的解决方法:

class A
class B
trait HighPrio

def f(implicit b: B) {}

implicit val a = new A with HighPrio

implicit def aToB(implicit a: A with HighPrio) = new B;
implicit def bToA(implicit b: B) = new A;

f

...不确定它是否适用于您的 Lift 机箱。

【讨论】:

  • 问题是这一行 implicit def vendorToVal[T](vendor: Vendor[T]) = vendor.vend 导致 any 隐式参数上的“发散隐式扩展”,因为存在相反的转换(从 T 到 Vendor[T])在范围内,似乎我无法摆脱它。
  • 也就是说情况是这样的:class A; class B; def f(implicit b: B) {}; implicit val a = new A; implicit def aToB(implicit a: A) = new B; implicit def bToA(implicit b: B) = new A; f
  • 再次感谢您的帮助,但还有一件事正在发生,可以通过以下方式说明:class A; case class Vendor[T](v: T); def f(implicit a: A) {}; implicit val vendor = Vendor(new A); implicit def vendorToVal[T](implicit v: Vendor[T]) = v.v; f
猜你喜欢
  • 2018-08-06
  • 1970-01-01
  • 2021-10-10
  • 1970-01-01
  • 1970-01-01
  • 2013-08-22
  • 2021-05-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多