我有一个带有类型参数的函数,我想知道该类型参数是否是一个Option
或不。我读过一些博文,即this one http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html最近关于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) {"Found Option!"} else {"Found something else."}
}
这似乎按预期工作:
scala> val x: Option[Int] = Some(3)
scala> myFunction(x)
res0: String = Found Option!
scala> val y: String = "abc"
scala> myFunction(y)
res1: String = Found something else.
如果是Some(3)
hitOption
是隐式参数,即使notOption
也会匹配(与A
= Option[Int]
)。显然,更具体的是选择的类型。但我能保证编译器总是选择更具体的类型吗?那么它在编译器中是如何工作的呢?我还没有找到这种行为的文档。
注意:也许这个问题的标题不是最好的,我很乐意将其更改为更好的标题。
已经有一个关于此的问题:Scala:隐式参数解析优先级 https://stackoverflow.com/questions/8623055/scala-implicit-parameter-resolution-precedence。它通过一个复杂的过程来回答自己博客文章 http://eed3si9n.com/revisiting-implicits-without-import-tax。我认为最重要的信息是 Martin Odersky 对博客文章的评论:
这是隐式搜索的更高级解释
在 Scala 中,这对应于规范的解释方式,但是在
稍微不那么形式主义的语言。
首先,我们寻找作为局部变量或作为封闭类和包的成员或作为导入可见的隐式变量 -
精确的规则是我们应该能够使用他们的名字来访问它们
仅,没有任何前缀。
如果在步骤 1 中没有找到隐式对象,我们将查看“隐式作用域”,其中包含带有某些功能的所有伴生对象。
与我们搜索的类型的关系(即
类型本身、其参数(如果有)以及其参数
超类型和超特质;重要性在于一般化
无需像 Haskell 一样进行整个程序分析
做)。
如果在任一阶段我们发现多个隐含的消歧
开始。消歧与重载完全相同
解决。静态重载解析解析规则有点
涉及到,这里就不重复了。如果有什么安慰的话:
Java 的规则和 C# 的规则比 Scala 的规则复杂得多
在这个区域。
现在根据这个解释,它是“静态重载解析规则”,它将消除之间的歧义notOption
and hitOption
。老实说,我不明白如何做到。
这个答案 https://stackoverflow.com/a/1887678/1374461解释说确实具有更具体参数的方法具有优先级,但我不知道这是否或如何与重载规则相关。
如果我是你,我不会太依赖这种行为,而是通过继承使用更容易理解的隐式优先级概念。无论如何,将隐含内容放入伴生对象中是个好主意。
归根结底,继承的隐式优先级较低。因此,可以安全地将隐含的内容退回到 ifhitOption
与伴生对象扩展的特征不匹配。
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._
.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)