简体   繁体   English

scala泛型方法重写

[英]scala generic method overriding

I have an abstract class : 我有一个抽象类:

abstract class Foo(...){
   def bar1(f : Foo) : Boolean
   def bar2(f : Foo) : Foo
}

multiple classes extend Foo and override the methods 多个类扩展Foo并覆盖方法

class FooImpl(...) extends Foo{
    override def bar1(f : Foo) : Boolean {
        ...
    }
    override def bar2(f : Foo) : Foo {
        ...
    }
} 

Is it possible, using generics (or something) to make the overriding methods have the parametertype of the subclass implementing it? 有可能,使用泛型(或其他东西)使重写方法具有实现它的子类的参数类型吗? Like this : 像这样 :

class FooImpl(...) extends Foo{
    override def bar1(f : FooImpl) : Boolean {
        ...
    }
    override def bar2(f : FooImpl) : FooImpl {
        ...
    }
}

I was thinking something along the line of the following, but that didn't seem to work... 我正在思考下面的内容,但这似乎不起作用......

abstract class Foo(...){
    def bar1[T <: Foo](f : T) : Boolean
    def bar2[T <: Foo](f : T) : T
}

class FooImpl(...) extends Foo{
    override def bar1[FooImpl](f : FooImpl) : Boolean {
       ...
    }
    override def bar2[FooImpl](f : FooImpl) : FooImpl{
       ...
    }
}

Any help is much appreciated! 任何帮助深表感谢!

Thank you. 谢谢。

abstract class Foo{
   type T <: Foo
   def bar1(f:T):Boolean
   def bar2(f:T):T
}

class FooImpl extends Foo{
   type T = FooImpl
   override def bar1(f:FooImpl) = true
   override def bar2(f:FooImpl) = f
}

In this version, different subclasses of Foo all share Foo as a superclass, but to hold the return value of bar2 (or the parameters to bar1 or bar2 ) in a setting where all you know about your object (let's say it's named obj ) is that it's a Foo , you need to use the type obj.T as the type of the variable. 在这个版本中, Foo不同子类都将Foo作为超类共享,但是在一个设置中保存bar2的返回值(或者将参数设置为bar1bar2 ),你知道你的对象(假设它的名字叫obj )它是一个Foo ,你需要使用obj.T类型作为变量的类型。

To make Ken Blum's second version a little bit nicer you can use self types: 为了使Ken Blum的第二个版本更好一点,你可以使用自我类型:

abstract class Foo[T] { self:T =>
   def bar1(f:T):Boolean
   def bar2(f:T):T
}

class FooImpl extends Foo[FooImpl]{
   override def bar1(f:FooImpl) = true
   override def bar2(f:FooImpl) = f
}

T needs to be a type parameter on the Foo class that you inherit from, not on the methods themselves. T需要是您继承的Foo类的类型参数,而不是方法本身。

abstract class Foo[T <: Foo[T]]{
   def bar1(f:T):Boolean
   def bar2(f:T):T
}

class FooImpl extends Foo[FooImpl]{
   override def bar1(f:FooImpl) = true
   override def bar2(f:FooImpl) = f
}

Different subclasses of Foo don't actually have a common supertype in this version of the code, because they extend from different parameterizations of Foo . 在这个版本的代码中, Foo不同子类实际上没有共同的超类型,因为它们从Foo不同参数化扩展而来。 You can use parameterized methods that refer to Foo[T] when you need to work with the common supertype, but I tend to prefer the abstract type solution I posted in my other answer, becuase it doesn't leak the details of the generics to all of the other functions that have to deal with Foos. 当你需要使用常见的超类型时,可以使用引用Foo[T]参数化方法,但我倾向于选择我在其他答案中发布的抽象类型解决方案,因为它不会泄漏泛型的细节到所有其他必须处理Foos的功能。

Ideally you combine things mentioned above, ie 理想情况下,你结合上面提到的东西,即

trait Foo[T <: Foo[T]] { self:T =>

"[T <: Foo[T]]" means T is subclass of Foo[T], AND "self:T =>" means that Foo[T] is subclass of T, and together it is a little weird way to tell that Foo[T] is exactly same as T. “[T <:Foo [T]]”表示T是Foo [T]的子类,AND“self:T =>”表示Foo [T]是T的子类,并且它是一种有点奇怪的方式告诉Foo [T]与T完全相同

Only with that I could make following code compile and work as intended: 只有这样我才能使下面的代码编译并按预期工作:

trait Field[T <: Field[T]] { self:T =>

  def x2:T

  def +(that:T):T

  def *(n:BigInt) : T = {
    if(n == 1)
      this
    else if(n == 2)
      this.x2
    else if(n == 3)
      this + this.x2
    else {
      val p = (this * (n/2)).x2
      if (n%2==0)
        p
      else
        p + this
    }        
  }

}

You can parameterize Foo to accomplish some of the effect easily: 您可以参数化Foo以轻松完成某些效果:

abstract class Foo[F <: Foo[F]] { def f: F }
class Food extends Foo[Food] { def f = this }  // Yay!
class Fool extends Foo[Food] { def f = new Food }  // Uh-oh...

If you want to rule out the second case, there's no straightforward way to do it with the current features in Scala. 如果你想排除第二种情况,那么使用Scala中的当前功能就没有直接的方法。

Also, some of what you seem to want doesn't make sense if you give an actual implementation in Foo . 另外,如果你在Foo给出一个实际的实现,你似乎想要的一些东西没有意义。 If Foo promises to take any Foo but you give it a method that insists on only a Food , it will break if you you pass it a different subclass of Foo (eg Fool ). 如果Foo承诺接受任何Foo但你给它一个只坚持Food的方法,如果你传递一个不同的Foo子类(例如Fool ),它将会破坏。 So the compiler won't let you do that. 所以编译器不会让你这样做。

abstract class Foo { def bar(f: Foo) : Foo }
class Foot extends Foo { def bar(f: Foo) = this }   // Fine!
class Fool extends Foo { def bar(f: Fool) = this }   // No good!

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

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