8

问题是为什么下面的代码不能与类型推断一起工作(下面是一个 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 
4

4 回答 4

5

我明白你为什么希望它工作,但是,显然,类型推断器没有使用返回类型来推断T。我也很期待。

至于歧义,CanBuildFrom通过不在同一“级别”中定义所有内容来避免歧义。例如,这解决了歧义问题:

trait LowPriorityImplicits {
  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)}
}

object UrlLike extends LowPriorityImplicits {
  implicit object str extends UrlLike[String]{def url(s: String) = s}
}

但是,它不会使类型推断按您想要的方式工作:

scala> res0.url : URL
<console>:16: error: type mismatch;
 found   : String
 required: java.net.URL
       res0.url : URL
            ^

这表明它显然在T不考虑返回类型的情况下进行推理。

于 2011-03-22T14:43:35.920 回答
4
> trait UrlLike[T] {

trait UrlLike[+T] {
于 2011-03-22T15:51:22.563 回答
2

关于任何隐含的歧义,规则是(从 Scala2.8 开始)

在比较重载方法或隐式方法的两种不同的适用替代方案时,每种方法:

  • 有更具体的论点得一分,
  • 以及在适当的子类中定义的另一点。

如果在这两个比较中获得更多分数,则替代方案“胜过”另一个。
这尤其意味着,如果备选方案具有相同的参数类型,则在子类中定义的参数类型获胜。

我不认为这些标准周围的隐含URLURI得到不同的点。

于 2011-03-22T14:14:02.723 回答
2

从您看到的错误报告中可能并不明显,但对象 UrlLike 中定义的所有三个隐式都导致了歧义(例如,尝试注释掉 uri 的定义,您会看到报告的歧义为在 str 和 url 之间)。

模棱两可的原因是 UrlSupport.url 的类型参数 T 仅受有可用的隐式 UrlLike 实例的要求限制。由于您的三个隐式对象提供的 UrlLike 实例,字符串、URL 和 URI 都同样很好地满足了该要求。编译器不会随意为您选择其中之一,因此它会报告歧义。

当然,除非您通过显式指定类型参数来解决歧义,就像您在最后两个 REPL 交互中所做的那样。

于 2011-03-22T14:20:45.203 回答