含糊不清的隐含意义

发布于 2024-10-25 09:14:36 字数 1644 浏览 1 评论 0原文

问题是为什么下面的代码不能使用类型推断(下面是一个 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

半山落雨半山空 2024-11-01 09:14:36

我可以理解为什么您希望它能够工作,但是,显然,类型推断器没有使用返回类型来推断 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
            ^

这表明它显然在不考虑返回类型。

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:

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}
}

However, it will not make the type inference work the way you want:

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

Which indicates it obviously makes T inference without taking into consideration the return type.

橘寄 2024-11-01 09:14:36
> trait UrlLike[T] {

trait UrlLike[+T] {
> trait UrlLike[T] {

trait UrlLike[+T] {
作死小能手 2024-11-01 09:14:36

关于任何隐式歧义,规则是(自 Scala2.8 起):

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

  • 有更多具体论点而得一分,
  • 还有一点在适当的子类中定义

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

我不认为 URLURI 周围的隐含内容会遵循这些标准获得一组不同的点。

Regarding any implicit ambiguity, the rule is (since Scala2.8):

When comparing two different applicable alternatives of an overloaded method or of an implicit, each method:

  • gets one point for having more specific arguments,
  • and another point for being defined in a proper subclass.

An alternative “wins” over another if it gets a greater number of points in these two comparisons.
This means in particular that if alternatives have identical argument types, the one which is defined in a subclass wins.

I don't think the implicits around URL or URI get a different set of points following those criteria.

深巷少女 2024-11-01 09:14:36

从您看到的错误报告中可能并不明显,但对象 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文