我使用scala 2.10.0-snapshot日期(20120522)并具有以下Scala文件:
这个定义了类型类和基本的类型类实例:
package com.netgents.typeclass.hole
case class Rabbit
trait Hole[A] {
def findHole(x: A): String
}
object Hole {
def apply[A: Hole] = implicitly[Hole[A]]
implicit val rabbitHoleInHole = new Hole[Rabbit] {
def findHole(x: Rabbit) = "Rabbit found the hole in Hole companion object"
}
}
Run Code Online (Sandbox Code Playgroud)
这是包对象:
package com.netgents.typeclass
package object hole {
def findHole[A: Hole](x: A) = Hole[A].findHole(x)
implicit val rabbitHoleInHolePackage = new Hole[Rabbit] {
def findHole(x: Rabbit) = "Rabbit found the hole in Hole package object"
}
}
Run Code Online (Sandbox Code Playgroud)
这是测试:
package com.netgents.typeclass.hole
object Test extends App {
implicit val rabbitHoleInOuterTest = new Hole[Rabbit] {
def findHole(x: Rabbit) = "Rabbit found the hole in outer Test object"
}
{
implicit val rabbitHoleInInnerTest = new Hole[Rabbit] {
def findHole(x: Rabbit) = "Rabbit found the hole in inner Test object"
}
println(findHole(Rabbit()))
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,Hole
是一个简单的类型类,它定义了一个Rabbit
试图找到的方法.我试图找出隐含的解决方案规则.
与所有四种类型类实例注释掉,scalac抱怨的歧义rabbitHoleInHolePackage
和rabbitHoleInHole
.(为什么?)
如果我发表评论rabbitHoleInHole
,scalac会编译并且我会回来"兔子在Hole包对象中找到了洞".(不应该在本地范围内隐含优先权吗?)
如果我再注释掉rabbitHoleInHolePackage
,scalac抱怨的歧义rabbitHoleInOuterTest
和rabbitHoleInInnerTest
.(为什么?在eed3si9n的文章中,下面列出了url,他发现内含和外部范围的含义可能有不同的优先权.)
如果我然后注释掉rabbitHoleInInnerTest
,scalac编译并且我回来了"兔子在外部测试对象中找到了洞".
正如您所看到的,上述行为并未遵循我在隐式解析中阅读的规则.我只描述了你在评论/取消注释实例时可以做的一小部分组合,其中大多数确实非常奇怪 - 我还没有进入导入和子类.
我已阅读并观看由suereth介绍,由索布拉尔计算器的答案,并通过eed3si9n一个非常复杂的回访,但我仍然大惑不解.
让我们从包对象中的隐式和禁用的类型类伴生开始:
\n\npackage rabbit {\n trait TC\n\n object Test extends App {\n implicit object testInstance1 extends TC { override def toString = "test1" }\n\n {\n implicit object testInstance2 extends TC { override def toString = "test2" }\n\n println(implicitly[TC])\n }\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\nScalac 查找范围内的任何隐式表达式,查找testInstance1
和testInstance2
。事实上,一个人处于更严格的范围内,只有当它们具有相同的名称时才有意义——适用正常的阴影规则。我们选择了不同的名称,并且没有一个隐式名称比另一个更具体,因此可以正确报告歧义。
让我们尝试另一个例子,这次我们将在本地范围中的隐式与包对象中的隐式进行比较。
\n\npackage rabbit {\n object `package` {\n implicit object packageInstance extends TC { override def toString = "package" }\n }\n\n trait TC\n\n object Test extends App {\n {\n implicit object testInstance2 extends TC { override def toString = "test2" }\n\n println(implicitly[TC])\n }\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n这里会发生什么?与之前一样,隐式搜索的第一阶段考虑调用站点范围内的所有隐式搜索。在这种情况下,我们有testInstance2
和packageInstance
。这些是不明确的,但在报告该错误之前,第二阶段开始,并搜索 的隐式范围TC
。
但这里的隐含范围是什么?TC
甚至没有一个伴生对象?我们需要回顾一下 Scala 参考文献 7.2 中的精确定义。
\n\n\n类型 T 的隐式作用域由与隐式参数\xe2\x80\x99s\n 类型关联的类的所有伴随模块\n (\xc2\xa75.4) 组成。在这里,如果类 C 是 T 的某些部分的基类 (\xc2\xa75.1.2),则我们说类 C 与类型 T 相关联。
\n\n类型的组成部分
\n\nT
是:\n
\n- 如果
\nT
是复合类型,\n 的各部分及其自身的并T1 with ... with Tn
集,T1, ..., Tn
T
- if
\nT
是参数化类型S[T1, ..., Tn]
, 和 部分的并集S
\nT1,...,Tn
,- 如果
\nT
是单例类型p.type
,则类型的部分p
,- if
\nT
是一个类型投影S#U
, 的部分S
以及T
它本身,- 在所有其他情况下,仅是
\nT
其本身。
我们正在寻找rabbit.TC
. 从类型系统的角度来看,这是: 的简写rabbit.type#TC
,其中rabbit.type
是表示包的类型,就好像它是常规对象一样。调用规则 4,得到零件TC
和p.type
。
那么,这一切意味着什么呢?简而言之,包对象中的隐式成员也是隐式作用域的一部分!
\n\n在上面的示例中,这为我们在隐式搜索的第二阶段提供了明确的选择。
\n\n其他的例子也可以用同样的方法来解释。
\n\n总之:
\n\n更新
\n\n在 Scala 2.9.2 中,行为有所不同并且是错误的。
\n\npackage rabbit {\n trait TC\n\n object Test extends App {\n implicit object testInstance1 extends TC { override def toString = "test1" }\n\n {\n implicit object testInstance2 extends TC { override def toString = "test2" }\n\n // wrongly considered non-ambiguous in 2.9.2. The sub-class rule\n // incorrectly considers:\n //\n // isProperSubClassOrObject(value <local Test>, object Test)\n // isProperSubClassOrObject(value <local Test>, {object Test}.linkedClassOfClass)\n // isProperSubClassOrObject(value <local Test>, <none>)\n // (value <local Test>) isSubClass <none>\n // <notype> baseTypeIndex <none> >= 0\n // 0 >= 0\n // true\n // true\n // true\n // true\n //\n // 2.10.x correctly reports the ambiguity, since the fix for\n //\n // https://issues.scala-lang.org/browse/SI-5354?focusedCommentId=57914#comment-57914\n // https://github.com/scala/scala/commit/6975b4888d\n //\n println(implicitly[TC])\n }\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n
归档时间: |
|
查看次数: |
1085 次 |
最近记录: |