如果泛型类型已经固定,如何使用隐式参数重写泛型方法?

发布于 2024-12-02 13:53:21 字数 629 浏览 1 评论 0原文

我尝试

def sum[B >: A](implicit num: Numeric[B]): B = ...

在类型 A 已固定为 Int 的子类中重写此方法。

我已经尝试过,

override def sum: Int = ...

但这当然不会覆盖,导致基于运行时动态类型的不同方法解析。

更进一步,

def sum[B >: Int](implicit num: Numeric[B]): Int

does override,而

def sum[B >: Int](implicit num: Numeric[Int]): Int

does not,以及

def sum(implicit num: Numeric[Int]): Int

为什么会这样?至少有可能摆脱多余的绑定B吗?

我不确定哪些类型和隐式可以省略,哪些必须保留,以便该方法仍然可以覆盖。

I try to override this method

def sum[B >: A](implicit num: Numeric[B]): B = ...

in a subclass where type A is already fixed to Int.

I already tried

override def sum: Int = ...

but this doesn't override of course, leading to different method resolution based on the dynamic type at runtime.

Going further,

def sum[B >: Int](implicit num: Numeric[B]): Int

does override, while

def sum[B >: Int](implicit num: Numeric[Int]): Int

does not, as well as

def sum(implicit num: Numeric[Int]): Int

Why is that the case? Is it at leats possible to get rid of the superfluous bound B?

I'm not sure which types and implicits I can leave out and what has to stay so that the method still overrides.

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

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

发布评论

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

评论(2

偏爱自由 2024-12-09 13:53:21

第一个问题是重写的方法需要相同数量和类型的类型参数,即使它们没有被使用。例如,

class C1 {
  def f[B] = println("hello")
}

class C2 extends C1 {
  override def f = println("world") // Error: f overrides nothing (needs parameter B)
}

除此之外,还存在健全性问题,因为 Numeric[A]A 中是不变的。这意味着只要 BC 存在,Numeric[B]Numeric[C] 之间就没有子类型关系。不同的。

想象 Numeric 是具有适当方差的特征,它仍然不起作用;显然,重写方法的签名需要完全相同:

class D1 {
  def g(x: Int) {}
}

class D2 extends D1 {
  override def g(x: Any) {} // Error: g overrides nothing (different parameter type)
}

我不确定为什么不能扩展重写方法的类型。 编辑:也许原因是与重载的兼容性,如

class D1 {
  def g(x: Any) {}
  def g(x: Int) {} // This is legal, even though the definitions seem to overlap
}

总结所示,当您重写时,必须保留方法的签名,包括类型参数。就您而言,这是您能做的最好的事情:

override def sum[B >: Int](implicit num: Numeric[B]): B = ...

The first problem is that overridden methods need the same number and kind of type parameters, even if they are not used. For example,

class C1 {
  def f[B] = println("hello")
}

class C2 extends C1 {
  override def f = println("world") // Error: f overrides nothing (needs parameter B)
}

Beyond this, there's also a problem with soundness since Numeric[A] is invariant in A. This means there is no subtype relationship between Numeric[B] and Numeric[C] whenever B and C are different.

Imagining that Numeric were a trait with the proper variance, it still wouldn't work; apparently, the signature of overridden methods needs to be exactly the same:

class D1 {
  def g(x: Int) {}
}

class D2 extends D1 {
  override def g(x: Any) {} // Error: g overrides nothing (different parameter type)
}

I'm not sure why the types of overridden methods can't be widened. Edit: Perhaps the reason is compatibility with overloading, as in

class D1 {
  def g(x: Any) {}
  def g(x: Int) {} // This is legal, even though the definitions seem to overlap
}

To summarize, when you override, you must preserve the signature of the method, including the type parameters. In your case, this is about the best you can do:

override def sum[B >: Int](implicit num: Numeric[B]): B = ...
野味少女 2024-12-09 13:53:21

好的,尝试解释为什么规则必须强制您保留带有隐式参数和方差的签名。

首先,隐式参数仍然是一个参数,它可以显式传递,并且除非它具有单例类型(这不是很有用),否则它的多个不同实例是可能的。

假设我创建

case class ZModulo(val p: Int) extends Numeric[Int] {
  def plus(a: Int, b: Int) = (a+b) % p
  // others along the same line
}

It 看起来像一个正确的NumericNumeric 文档没有说明应该遵循哪些定律,但 ZModulo 并非没有道理。

现在,

class Summable[A] {
  def sum[B >: A](implicit num: Numeric[A]): B =...
}

如果我有 val ints : Summable[Int],我当然可以调用 ints.Sum(ZModulo(3))。因此,如果您的类是 Summable[Int] 的子类,它必须允许我这样做。因此您无法删除 Numeric 参数。

其次,假设我带有一个Numeric[Any]。不知道如何对数字合理地做到这一点,但规范和编译器无法知道这一点。无论如何,他们也必须接受不合理的实施。因此,让

object MixThemAll : Numeric[A] {...}

Summable 中的签名允许 ints.sum(MixThemAll)。所以你的子类也必须允许这样做。

因此,让您删除子类中的隐式参数或方差是不合理的。

Ok, trying to explain why the rules must force you to keep the signature with implicit parameter and variance.

First, animplicit argument is still an argument, it can be passed explicitely, and except maybe when it has a singleton type (which would not be very useful), several different instances of it are possible.

Suppose I create

case class ZModulo(val p: Int) extends Numeric[Int] {
  def plus(a: Int, b: Int) = (a+b) % p
  // others along the same line
}

It seems like a proper Numeric. Numeric documentation does not say which laws should be expected, but ZModulo is not unreasonable.

Now there is your

class Summable[A] {
  def sum[B >: A](implicit num: Numeric[A]): B =...
}

If I have val ints : Summable[Int], I am certainly allowed to call ints.Sum(ZModulo(3)). So if your class is to be a subclass of Summable[Int], it must allow me that. So you cannot remove the Numeric parameter.

Second, suppose I come with a Numeric[Any]. Not sure how I could do that reasonably for a numeric, but the spec and the compiler can't know that. And anyway, they must accept unreasonable implementations too. So let's have

object MixThemAll : Numeric[A] {...}

The signature in Summable allows ints.sum(MixThemAll). So your subclass must allow that too.

So letting you remove either implicit parameter or variance in the subclass would be unsound.

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