【问题标题】:Type class pattern in Scala doesn't consider inheritance?Scala中的类型类模式不考虑继承?
【发布时间】:2010-10-06 06:29:14
【问题描述】:

在某些情况下,我正在使用类型类设计 API,但是我遇到了隐式解析的问题。如下所示,如果存在类型 A 的隐式对象,但将 B extends A 类型的对象传递给方法,则找不到隐式对象。有没有办法使这项工作或调用者必须将隐式对象放入每个子类的范围内?

这是一个例子:

class A
class B extends A

class T[+X]

object T {
  implicit object TA extends T[A]
}

def call[X:T](x:X) = println(x)

// compiles
call(new A)
// doesn't compile
call(new B)

var a = new A
// compiles
call(a)

a = new B
// compiles
call(a)

val b = new B
// doesn't compile
call(b)

编译失败,输出如下:

/private/tmp/tc.scala:16:错误:找不到 this.T[this.B] 类型的证据参数的隐式值 呼叫(新B) ^ /private/tmp/tc.scala:28:错误:找不到 this.T[this.B] 类型的证据参数的隐式值 呼叫(b)

【问题讨论】:

  • 我还尝试将调用的定义更改为: def call[X,X2 <: x x2:t println>

标签: inheritance scala implicit typeclass


【解决方案1】:

调用call(new B) 表示call[B](new B)(tB) 使得tb 属于T[B] 类型或其子类。 (期望 T 类型参数的方法只能期望 T 或 T 的子类,例如,def foo(s: String) 不能使用 Any 类型的参数调用)。 T[A] 不是 T[B] 的子类型

要修复,您可以将 T 更改为定义为 T[-X]。这意味着编译器会将 T[A] 视为 T[B] 的子类型

【讨论】:

  • 问题是,即使你还定义了implicit object TB extends T[B]implicitly[T[B]] == T.TAlampsvn.epfl.ch/trac/scala/ticket/2509
  • 听起来很合理,因为 TA 比 TB 更具体,并且 TA is-a TB 所以应该可以在 T[B] 所在的地方使用。如果您希望隐式与类型完全匹配,请将 T 定义为 T[X]
【解决方案2】:

以下工作正常:

scala> def call[X](x: X)(implicit evidence: T[X]<:<T[X])  = println(x)
call: [X](x: X)(implicit evidence: <:<[T[X],T[X]])Unit

scala> call(new A)
line0$object$$iw$$iw$A@1d869b2

scala> call(new B)
line2$object$$iw$$iw$B@b3a5d1

scala> val b = new B
b: B = B@30e4a7

scala> call(b)
line2$object$$iw$$iw$B@30e4a7

在您的情况下编译失败,因为def call[X:T](x:X) = println(x) 被视为call: [X](x: X)(implicit evidence$1: T[X])Unit。为了传递子类型,您可以使用广义类型约束。

【讨论】:

  • 有没有办法真正获得证据$1?例如,假设 T 是一个函数,x 是参数。我不能调用证据(x)
  • 为什么不能?你可以通过名称evidence$1 来调用它,就像任何其他 [隐式] 参数一样。
  • 如果方法上有多个类型参数,会有evidence$1、evidence$2等:[X,Z](x: X)(implicit evidence$1: T[X],implicit evidence$2: T[Z])Unit
  • 我的问题并没有完全满足我的需求。我喜欢学习这个技巧,但我的实际需求是:trait T[X] extends Function1[X,Boolean]。并且调用是:def call[X](x:X)(implicit x2:T[X]) = x2(x)。原来使用 T[-X] 对我有用。很酷地了解 <:>
  • def foo[A: M] = { val ma = implicitly[M[A]; ... }
【解决方案3】:

试试这个:

object T {
  implicit def TA[X <: A] = new T[X]
}

import T._

或者简单地说:

implicit def TA[X <: A] = new T[X]

【讨论】:

    猜你喜欢
    • 2020-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-15
    • 1970-01-01
    • 2021-04-14
    • 2013-08-29
    • 1970-01-01
    相关资源
    最近更新 更多