含糊不清的含义

时间:2011-03-22 12:53:19

标签: scala implicits

问题是为什么下面的代码不能用于类型推断(下面是一个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 个答案:

答案 0 :(得分: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推理。

答案 1 :(得分:4)

> trait UrlLike[T] {

trait UrlLike[+T] {

答案 2 :(得分:2)

关于任何隐含的歧义,rule is (since Scala2.8)

  

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

     
      
  • 获得一点具有更多具体参数
  •   
  • 另一点是在一个合适的子类中定义
  •   
     

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

我不认为URLURI附近的含义会按照这些标准获得不同的点数。

答案 3 :(得分:2)

从您看到的错误报告中可能并不明显,但是对象UrlLike中定义的所有三个含义都会导致歧义(例如,尝试评论uri的定义,您会看到模糊性报告为在str和url之间。)

模糊性的原因是UrlSupport.url的类型参数T仅受到可用的隐式UrlLike实例的要求的限制。感谢三个隐式对象提供的UrlLike实例,String,URL和URI都同样满足该要求。编译器不会随意选择其中一个,因此它会报告歧义。

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