13

假设我们有以下两个特征:

trait Foo[A] { def howMany(xs: List[A]) = xs.size }
trait Bar

以及从第二个到第一个的隐式转换:

implicit def bar2foo[A](bar: Bar) = new Foo[A] {}

我们创建一个Bar和一个整数列表:

val bar = new Bar {}
val stuff = List(1, 2, 3)

现在我希望以下工作:

bar howMany stuff

但它没有:

scala> bar howMany stuff
<console>:13: error: type mismatch;
 found   : List[Int]
 required: List[A]
              bar howMany stuff
                          ^

所以我们去规范,它有这样的说法(粗体强调的是我的):

视图适用于三种情况。

  1. [这里不相关。]

  2. 在类型为Te选择em中,如果选择器m不表示T的成员。在这种情况下,搜索适用于e并且其结果包含名为m的成员的视图v。搜索与隐式参数的情况一样进行,其中隐式范围是T之一。如果找到这样的视图,则将选择em转换为v(e).m

  3. 在类型为Te的选择em(args)中,如果选择器m表示 T 的某些成员但这些成员都不适用于参数args。在这种情况下,搜索适用于e并且其结果包含 适用于args的方法m的视图v。搜索与隐式参数的情况一样进行,其中隐式范围是T之一。如果找到这样的视图,则选择em将转换为 v(e).m(args)

所以我们尝试以下方法,认为它一定太荒谬了:

trait Foo[A] { def howMany(xs: List[A]) = xs.size }
trait Bar { def howMany = throw new Exception("I don't do anything!") }

implicit def bar2foo[A](bar: Bar) = new Foo[A] {}

val bar = new Bar {}
val stuff = List(1, 2, 3)

但它确实(至少在 2.9.2 和 2.10.0-RC2 上):

scala> bar howMany stuff
res0: Int = 3

这会导致一些非常奇怪的行为,例如在这个问题的解决方法中。

我有三个(密切相关的)问题:

  1. 是否有一种直接的方法(即,不涉及添加具有适当名称的假方法)在上述原始案例中正确应用视图?
  2. 有人可以提供解释这种行为的规范吗?
  3. 假设这是预期的行为,它是否有任何意义?

我也很感谢以前讨论过这个问题的任何链接——我对谷歌的运气并不好。

4

5 回答 5

1

这似乎是一个错误,所以我的答案是:

  1. 搜索针对 Scala 编译器报告的类似错误,如果未找到,请报告新错误https://issues.scala-lang.org/
  2. 在这种情况下,规范的那部分似乎并不重要,因为它没有谈论类型推断
  3. 对我没有任何意义

PS。在 2.8.1 中,将虚拟方法添加到 Bar 的解决方法不会使其编译。

于 2012-11-22T18:07:55.360 回答
1

供大家参考,这只能是一个错误。您知道的方式是错误消息:

<console>:13: error: type mismatch;
 found   : List[Int]
 required: List[A]

List[A] 不是真正的类型 - 它是 List 应用于它自己的类型参数。这不是一种可以被要求的类型,因为它不是一种可以表达的类型。

[编辑——太早了,谁知道我在说什么。忽略以上内容,但您仍然可以点击链接。]

相关票证是https://issues.scala-lang.org/browse/SI-6472

于 2012-12-06T17:26:46.587 回答
0

用这个替换你的 Foo:

trait Foo[_] { def howMany(xs: List[_]) = xs.size }

它有效,这对我来说也更有意义,因为你对 A 绝对不感兴趣。

于 2012-11-22T15:32:02.800 回答
0

您的隐式转换似乎完全按照您告诉它的方式进行。

implicit def bar2foo[A](bar: Bar) = new Foo[A] {}

将 Bar 转换为新Foo[A]对象。所以反过来

scala> bar howMany stuff
<console>:13: error: type mismatch;
 found   : List[Int]
 required: List[A]
              bar howMany stuff

它寻找“A”类型。

为了使这项工作按照您想要的方式进行(我认为),您可以在函数上执行它,而不是定义特征的视图。

trait Foo { def howMany[A](xs: List[A]) = xs.size }
trait Bar
implicit def bar2foo[A](bar: Bar) = new Foo{}
val bar = new Bar {}
val stuff = List(1, 2, 3)

那么它应该会给你你想要的结果。

scala> bar howMany stuff
res0: Int = 3

或者您可以在隐式函数上定义视图

trait Foo[A] { def howMany(xs: List[A]) = xs.size }
trait Bar

implicit def bar2foo[A](bar: Bar) = new Foo[Int] {}

val bar = new Bar {}
val stuff = List(1, 2, 3)

我个人认为在函数上定义它更干净。

于 2012-11-22T16:10:44.160 回答
0

这虽然丑陋,但似乎有效:

(bar: Foo[Int]) howMany stuff
于 2012-11-22T20:50:26.640 回答