在scala中,类型类解析是如何工作的?

14 浏览
0 Comments

在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])。显然,选择更具体的类型。但是我能保证编译器总是选择更具体的类型吗?编译器是如何工作的呢?我还没有找到这种行为的文档。

注意:也许这个问题的标题不是最好的,我很愿意为它换个更好的标题。

0
0 Comments

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._导入它们,这种解决方法也适用。

谢谢,所以消歧是我忽略的术语。在规范中关于重载解析的章节中有一些关于“更具体”的定义,但我需要一些时间来理解它。与此同时,我喜欢你提出的替代解决方案,这是确保有效的方法。

0