含糊不清的隐含意义
问题是为什么下面的代码不能使用类型推断(下面是一个 REPL 会话来演示),它可以修复吗?更具体地说,这与编译器用来推断返回类型的 CanBuildFrom 的使用有何不同?
鉴于此代码:
object S {
import java.net._
trait UrlLike[T] {
def url(s: String): T
}
object UrlLike {
implicit object str extends UrlLike[String]{def url(s: String) = s}
implicit object url extends UrlLike[URL]{def url(s: String) = new URL(s)}
implicit object uri extends UrlLike[URI]{def url(s: String) = new URI(s)}
}
trait UrlSupport {
val _url: String
def url[T : UrlLike]: T = implicitly[UrlLike[T]].url(_url)
}
}
我在 REPL (2.8.1) 中有此会话:
scala> :load c:\temp\UrlTest.scala
Loading c:\temp\UrlTest.scala...
defined module S
scala> import java.net._
import java.net._
scala> import S._
import S._
scala> new UrlSupport{val _url = "http://example.com"}
res0: java.lang.Object with S.UrlSupport = $anon$1@155bd22
scala> res0.url : String
<console>:14: error: ambiguous implicit values:
both object uri in object UrlLike of type object S.UrlLike.uri
and object url in object UrlLike of type object S.UrlLike.url
match expected type S.UrlLike[T]
res0.url : String
^
scala> res0.url : URL
<console>:14: error: ambiguous implicit values:
both object uri in object UrlLike of type object S.UrlLike.uri
and object url in object UrlLike of type object S.UrlLike.url
match expected type S.UrlLike[T]
res0.url : URL
^
scala> res0.url[String]
res3: String = http://example.com
scala> res0.url[URL]
res4: java.net.URL = http://example.com
The question is why doesn't the following code work with type inference (below is a REPL session to demonstrate), and can it be fixed? More specifically, how is this different from the use of CanBuildFrom which the compiler uses to infer the return type?
Given this code:
object S {
import java.net._
trait UrlLike[T] {
def url(s: String): T
}
object UrlLike {
implicit object str extends UrlLike[String]{def url(s: String) = s}
implicit object url extends UrlLike[URL]{def url(s: String) = new URL(s)}
implicit object uri extends UrlLike[URI]{def url(s: String) = new URI(s)}
}
trait UrlSupport {
val _url: String
def url[T : UrlLike]: T = implicitly[UrlLike[T]].url(_url)
}
}
I have this session in the REPL (2.8.1):
scala> :load c:\temp\UrlTest.scala
Loading c:\temp\UrlTest.scala...
defined module S
scala> import java.net._
import java.net._
scala> import S._
import S._
scala> new UrlSupport{val _url = "http://example.com"}
res0: java.lang.Object with S.UrlSupport = $anon$1@155bd22
scala> res0.url : String
<console>:14: error: ambiguous implicit values:
both object uri in object UrlLike of type object S.UrlLike.uri
and object url in object UrlLike of type object S.UrlLike.url
match expected type S.UrlLike[T]
res0.url : String
^
scala> res0.url : URL
<console>:14: error: ambiguous implicit values:
both object uri in object UrlLike of type object S.UrlLike.uri
and object url in object UrlLike of type object S.UrlLike.url
match expected type S.UrlLike[T]
res0.url : URL
^
scala> res0.url[String]
res3: String = http://example.com
scala> res0.url[URL]
res4: java.net.URL = http://example.com
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我可以理解为什么您希望它能够工作,但是,显然,类型推断器没有使用返回类型来推断
T
。我也很期待。至于歧义,
CanBuildFrom
通过不在同一“级别”中定义所有内容来避免歧义。例如,这解决了歧义问题:但是,它不会使类型推断按照您想要的方式工作:
这表明它显然在不考虑返回类型。
I can see why you'd expect it to work, but, obviously, the type inferencer isn't using the return type to infer
T
. I'd expect it too as well.As for the ambiguity,
CanBuildFrom
avoids being ambiguous by just not defining everything in the same "level". For instance, this solves the ambiguity problem:However, it will not make the type inference work the way you want:
Which indicates it obviously makes
T
inference without taking into consideration the return type.关于任何隐式歧义,规则是(自 Scala2.8 起):
我不认为
URL
或URI
周围的隐含内容会遵循这些标准获得一组不同的点。Regarding any implicit ambiguity, the rule is (since Scala2.8):
I don't think the implicits around
URL
orURI
get a different set of points following those criteria.从您看到的错误报告中可能并不明显,但对象 UrlLike 中定义的所有三个隐式都导致了歧义(例如,尝试注释掉 uri 的定义,您将看到报告的歧义在 str 和 url 之间)。
产生歧义的原因是 UrlSupport.url 的类型参数 T 仅受存在可用的隐式 UrlLike 实例的要求的限制。由于三个隐式对象提供的 UrlLike 实例,字符串、URL 和 URI 都同样很好地满足了该要求。编译器不会任意为您选择其中之一,因此它会报告歧义。
当然,除非您通过显式指定类型参数来解决歧义,就像您在最后两次 REPL 交互中所做的那样。
It might not be obvious from the error report that you're seeing, but all three of the implicits defined in object UrlLike are contributing to the ambiguity (eg. try commenting out the definition of uri and you'll see the ambiguity reported as being between str and url).
The reason for the ambiguity is that the type parameter T of UrlSupport.url is bounded only by the requirement that there be an implicit UrlLike instance available for it. String, URL and URI all satisfy that requirement equally well thanks the UrlLike instances provided by your three implicit objects. The compiler isn't going to choose one of those for you arbitrarily, so it reports an ambiguity.
Unless, of course, you resolve the ambiguity by explicitly specifying the type argument, as you've done in the last two of your REPL interactions.