简体   繁体   English

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

[英]How to override a generic method with implicit arguments if the generic type is already fixed?

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 . 在类型A已经固定为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 ? 是否有可能摆脱多余的绑定B

I'm not sure which types and implicits I can leave out and what has to stay so that the method still overrides. 我不确定可以保留哪些类型和隐式内容,必须保留哪些内容,以便该方法仍然可以重写。

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 . 除此之外,由于Numeric[A]A不变,因此在健全性方面也存在问题。 This means there is no subtype relationship between Numeric[B] and Numeric[C] whenever B and C are different. 这意味着只要BC不同, Numeric[B]Numeric[C]之间就不会存在子类型关系。

Imagining that Numeric were a trait with the proper variance, it still wouldn't work; 想象Numeric是具有适当方差的特征,它仍然行不通。 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 = ...

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 Numeric documentation does not say which laws should be expected, but ZModulo is not unreasonable. Numeric文档并没有说明应该ZModulo哪些法律,但是ZModulo并非没有道理。

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)) . 如果我有val ints : Summable[Int] ,当然可以调用ints.Sum(ZModulo(3)) So if your class is to be a subclass of Summable[Int] , it must allow me that. 因此,如果您的班级要成为Summable[Int]的子类,则必须允许我这样做。 So you cannot remove the Numeric parameter. 因此,您无法删除Numeric参数。

Second, suppose I come with a Numeric[Any] . 其次,假设我带有一个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) . Summable中的签名允许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. 因此,让您删除隐式参数或子类中的方差将是不明智的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM