Scala 中的类型类模式不考虑继承?

发布于 2024-09-26 10:41:31 字数 751 浏览 1 评论 0原文

在某些情况下,我正在使用类型类设计 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: error: could not find implicit value for evidence parameter of type this.T[this.B]
call(new B)
    ^
/private/tmp/tc.scala:28: error: could not find implicit value for evidence parameter of type this.T[this.B]
call(b)

I am designing an API using type classes in some cases however I have encountered a problem with implicit resolution. As shown below, if there is an implicit object for type A but an object of type B extends A is passed to the method, then an implicit object cannot be found. Is there a way to make this work or do callers have to put implicit objects into scope for each subclass?

Here is an example:

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)

This fails to compile with the following output:

/private/tmp/tc.scala:16: error: could not find implicit value for evidence parameter of type this.T[this.B]
call(new B)
    ^
/private/tmp/tc.scala:28: error: could not find implicit value for evidence parameter of type this.T[this.B]
call(b)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

箹锭⒈辈孓 2024-10-03 10:41:31

调用call(new B)意味着call[B](new B)(tB),使得tb是T[B]类型或其子类。 (需要 T 类型参数的方法只能需要 T 或 T 的子类,例如,不能使用 Any 类型参数调用 def foo(s: String)) 。 T[A] 不是 T[B] 的子类型

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

The call call(new B) means call[B](new B)(tB) such that tb is of type T[B] or subclass of it. (A method that expects argument of type T can only expect T or subclass of T, e.g., def foo(s: String) cannot be called with argument of type Any). T[A] is not a subtype of T[B]

To fix, you can change T to be defined T[-X]. This means that the compiler will consider T[A] to be a subtype of T[B]

情话难免假 2024-10-03 10:41:31

以下工作正常:

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)(隐式证据$1: T[X])单位。为了传递子类型,您可以使用广义类型约束。

The following works fine:

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

In your case compilation fails, because def call[X:T](x:X) = println(x) is treated as call: [X](x: X)(implicit evidence$1: T[X])Unit. In order to pass the subtype, you may use generalized type constraints.

二智少女 2024-10-03 10:41:31

试试这个:

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

import T._

或者简单地:

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

Try this:

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

import T._

or simply:

implicit def TA[X <: A] = new T[X]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文