2

这无法使用 Scala 2.10 编译

object TestImplicits {
  class View
  implicit class RichView[A <: View](v: A) {
    def onClicked() = println(v + " was clicked")
  }
  implicit def intToView[A <: View](i: Int): A = ???
  implicit def intToRichView(id: Int): RichView[View] = ???
  1.onClicked()
}

错误如下:

<console>:20: error: type mismatch;
 found   : Int(1)
 required: ?{def onClickedd: ?}
Note that implicit conversions are not applicable because they are ambiguous:
 both method intToView in object TestImplicits of type [A <: TestImplicits.View]
(i: Int)A
 and method intToRichView in object TestImplicits of type (id: Int)TestImplicits
.RichView[TestImplicits.View]
 are possible conversion functions from Int(1) to ?{def onClickedd: ?}
                  1.onClickedd()
                  ^

但是等等,View 类没有方法onClicked!这就是我遇到问题的原因:

  • 当我使用它来实现我的第二个函数时,我无法删除第一个隐式函数。
  • 如果我删除第二个隐式函数,我将失去电源功能。

我怎样才能同时保留两者?

更新

如果我更改1.onClicked()intToView(1).onClicked(),我会收到以下有趣的错误:

<console>:20: error: value onClicked is not a member of Nothing
                  intToView(1).onClicked()
                               ^

如果有人可以向我解释这一点,我将不胜感激。

4

2 回答 2

3

真正的问题是您的intToView方法从根本上说没有意义,也无法有效地实现。

现在它实际上是在说“给我一个整数并告诉我一个 的子类型View,我会给你一个该子类型的实例”。但这是不可能的,因为我可以发明一些非常混乱的类来扩展View. 例如:

class NamedView(val name: String) extends View

您的方法的类型签名intToView承诺以下内容应该有效:

val viewName: String = intToView[NamedView](13).name

这可能是什么?你怎么能intToView以这样一种方式实现,它会知道如何创建一个NamedView我刚刚在现场制作的?

所以???允许你编写一个可以编译但没有意义的方法。这是一种危险的情况,因为这意味着编译器可能会做各种愚蠢的事情。

在这种情况下,它所做的愚蠢的事情是决定它在这里真正拥有的是从Intto的隐式转换Nothing,当然Nothing是 的子类型RichView[_],所以它也有从Intto的隐式转换RichView[_]Int然后你给它另一个从to 的隐式转换RichView[_],它就会窒息。

在这种情况下,最简单的解决方案是从 中删除类型参数intToView

implicit def intToView(i: Int): View = ???

这是否适用于您的实际用例取决于您正在尝试做什么。

于 2013-07-03T14:23:08.713 回答
0

这是我涵盖诸如 TextView 等情况的解决方案:我从通用函数中删除了隐式函数,并显式添加了隐式函数以将 id 转换为视图。这样,我可以拥有我想要的所有方面。

object TestImplicits {
  class View
  class TextView extends View { def setText(s: String): Unit = println(s"text set! $s"}
  implicit class RichView(v: View) {
    def onClicked() = println(s"$v was clicked")
  }
  def intToView[A <: View](id: Int): A = findViewById(id).asInstanceOf[A]
  implicit def intToTextView(id: Int): TextView = intToView[TextView](id)
  implicit def intToRichView(id: Int): RichView[View] = new RichView(intToView[View](id))
  1.onClicked()
  2.setText("my text")
}
于 2013-07-11T16:53:47.847 回答