9

考虑以下代码:

object foo {

    trait Bar[Q[_]]

    implicit object OptionBar extends Bar[Option]

    def test[T, C[_]](c: C[T])(implicit bar: Bar[C]) = ()

    def main(args: Array[String]) {
      test(Some(42): Option[Int])  //???
    }
}

这可行,但我需要将 Some(42) 键入为 Option[Int],否则将无法解析隐式对象 OptionBar(因为需要使用 Bar[Some])。有没有办法避免显式键入,以便即使我用 Some 或 None 提供测试,我也会在测试中获得隐式 OptionBar 对象?

[澄清]

  • 我在这里使用了 Option 作为示例,如果我有Bar一个抽象类等,它也应该可以工作。
  • 当其他不相关的条在范围内时,该解决方案也应该起作用,例如implicit object listBar extends Bar[list]

[更新]

似乎使 Bar 的参数逆变可以解决问题:

object foo {

  trait Bar[-Q[_]] //<---------------

  implicit object OptionBar extends Bar[Option]
  implicit object ListBar extends Bar[List]

  def test[T, C[_]](c: C[T])(implicit bar: Bar[C]) = ()

  def main(args:Array[String]) {
    test(Some(42))
  }
}

但当然这是对 Bar 可能性的严重限制,所以我仍然希望有更好的答案。

4

2 回答 2

7

它并非在所有情况下都有效,但如前所述,您可以试试这个:

object foo {
  trait Bar[Q[_]]

  implicit object OptionBar extends Bar[Option]

  def test[T, C[_], D](c: D)(implicit bar: Bar[C], ev: D <:< C[T]) = ()

  def main(args: Array[String]) {
    test(Some(42)) //???
  }
}

有趣的是,这并没有推断出来,尽管它表达了同样的事情:

def test[T, C[_], D <: C[T]](c: D)(implicit bar: Bar[C]) = ()

要了解有关 的更多信息<:<,请参阅:

于 2010-09-28T20:06:19.543 回答
5

那是因为Some(42)是一种比Option[Int]. 它是一个Some[Int]. 请参阅下面的替代编码:

object foo {

    trait Bar[Q[_]]

    implicit object OptionBar extends Bar[Option]

    def test[T, C[_]](c: C[T])(implicit bar: Bar[C]) = ()

    def main(args: Array[String]) {
      test(Option(42))
    }
}
于 2010-09-28T20:18:25.407 回答