【问题标题】:How can I combine the typeclass pattern with subtyping?如何将类型类模式与子类型结合起来?
【发布时间】:2011-10-04 16:46:50
【问题描述】:

假设我在 Scala 中使用类型类模式。这是我制作 C 类的方法 类型类 Foo 的一部分:

Welcome to Scala version 2.9.0.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_26).

scala> trait Foo[T] { def foo(t: T) }
defined trait Foo

scala> def foo[T : Foo](t: T) { implicitly[Foo[T]].foo(t) }
foo: [T](t: T)(implicit evidence$1: Foo[T])Unit

scala> class C
defined class C

scala> foo(new C)
<console>:11: error: could not find implicit value for evidence parameter of type Foo[C]
       foo(new C)
          ^

scala> implicit object FooC extends Foo[C] { override def foo(c: C) { println("it's a C!") } }
defined module FooC

scala> foo(new C)
it's a C!

到目前为止一切顺利。但是假设我有一个 C 的子类 D,并且我希望 D 的实例也“在”类型类中:

scala> class D extends C
defined class D

scala> foo(new D)
<console>:13: error: could not find implicit value for evidence parameter of type Foo[D]
       foo(new D)
          ^

哇!如何在不必为 D 显式提供类型类实例的情况下完成这项工作?

【问题讨论】:

标签: scala typeclass variance


【解决方案1】:

对此有不同的可能解决方案,具体取决于我是要仅针对 C 解决问题,还是要为整个类型类解决问题 .

仅适用于 C,而不是 implicit object FooC ... 我们说:

implicit def CIsFoo[T <: C]: Foo[T] =
  new Foo[T] { override def foo(t: T) { println("it's a C!") } }

要修复所有的 Foo,使其具有逆变性:

trait Foo[-T] { def foo(t: T) }

或者如果由于某种原因您不能或不想这样做,您可以将 def foo... 替换为:

def foo[T](t: T)(implicit foo: Foo[_ >: T]) =
  foo.foo(t)

(感谢#scala denizens Daniel Sobral 和 Stefan Zeiger 的帮助。)

更新 2011 年 9 月 20 日,包括“使 Foo 逆变”解决方案,我错过了

【讨论】:

  • 这里隐藏着另一个问题...如果我希望 D 的处理方式与 T 略有不同,共享一些通用代码!
  • @jsuereth 没有什么可以阻止您像为C 那样为D 声明implicit object FooD,并从FooD 中的FooC 调用方法。
  • 其实你应该试试。 '冲突的隐式导入',除非你搞砸了优先级。完整的解决方案看起来很像样样,可能会令人沮丧。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-06
  • 2020-04-22
  • 2013-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多