在scala中,类型类解析是如何工作的?
在scala中,类型类解析是如何工作的?
我有一个带有类型参数的函数,并且我想找出类型参数是否是Option
。我最近阅读了一些关于scala中类型类的博客文章,比如这篇文章,所以我想出了这个解决方案:
case class OptionFinder[A](isOption: Boolean) implicit def notOption[A]: OptionFinder[A] = OptionFinder(false) implicit def hitOption[A]: OptionFinder[Option[A]] = OptionFinder(true) def myFunction[A](value: A)(implicit optionFinder: OptionFinder[A]): String = { if (optionFinder.isOption) {"找到了Option!"} else {"找到了其他东西。"} }
这似乎按预期工作:
scala> val x: Option[Int] = Some(3) scala> myFunction(x) res0: String = 找到了Option! scala> val y: String = "abc" scala> myFunction(y) res1: String = 找到了其他东西。
在Some(3)
的情况下,hitOption
是隐式参数,即使notOption
也可以匹配(使用A
= Option[Int]
)。显然,选择更具体的类型。但是我能保证编译器总是选择更具体的类型吗?编译器是如何工作的呢?我还没有找到这种行为的文档。
注意:也许这个问题的标题不是最好的,我很愿意为它换个更好的标题。
Scala中的类型类解析是如何工作的?
在Scala中,类型类解析是通过隐式参数实现的。在查找隐式参数时,Scala会遵循一定的规则和顺序。首先,它会查找当前作用域中可见的隐式参数,包括局部变量、封闭类和包中的成员,以及导入的隐式参数。如果在第一步中找不到隐式参数,接下来会查找“隐式作用域”,该作用域包含与所需类型相关的所有伴生对象(包括类型本身的伴生对象、其参数的伴生对象(如果有)以及其超类型和超trait的伴生对象)。如果在任一步骤中找到多个隐式参数,则会进行消歧。消歧的规则与重载解析相同。
根据这个解释,静态重载解析规则将在notOption和hitOption之间进行消歧。但是,对于这一点我不太清楚。
根据这个答案解释,确实具有更具体参数的方法优先级更高,但我不知道这与重载规则有何关联。
如果我是你的话,我不会过分依赖这种行为,而是使用更容易理解的继承中的隐式优先级概念。将隐式参数放在伴生对象中是一个好主意。
总之,继承的隐式具有较低的优先级。因此,如果hitOption不匹配,则将回退到伴生对象扩展的trait中的隐式参数。
以下代码示例展示了如何实现这种解决方法:
case class OptionFinder[A](isOption: Boolean) object OptionFinder extends LowerPriority { implicit def hitOption[A]: OptionFinder[Option[A]] = OptionFinder(true) } trait LowerPriority { implicit def notOption[A]: OptionFinder[A] = OptionFinder(false) } def myFunction[A](value: A)(implicit optionFinder: OptionFinder[A]): String = { if (optionFinder.isOption) {"Found Option!"} else {"Found something else."} }
如果将隐式参数放在非伴生对象MyImplicits中,并使用import MyImplicits._
导入它们,这种解决方法也适用。
谢谢,所以消歧是我忽略的术语。在规范中关于重载解析的章节中有一些关于“更具体”的定义,但我需要一些时间来理解它。与此同时,我喜欢你提出的替代解决方案,这是确保有效的方法。