Scala:使用具体实例的返回类型实现方法 [英] Scala: implementing method with return type of concrete instance

查看:115
本文介绍了Scala:使用具体实例的返回类型实现方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一种方法来强制抽象类中的方法具有其调用对象的 concrete 类的返回类型.最常见的示例是copy()方法,我目前正在使用基于抽象类型的方法:

I need a way to enforce a method in an abstract class to have a return type of the concrete class of the object it is called on. The most common example is a copy() method, and I'm currently using an approach based on abstract types:

abstract class A(id: Int) {
  type Self <: A
  def copy(newId: Int): Self
}

class B(id: Int, x: String) extends A(id) {
  type Self = B
  def copy(newId: Int) = new B(newId, x)
}

class C(id: Int, y: String, z: String) extends A(id) {
  type Self = C
  def copy(newId: Int) = new C(newId, y, z)
}

我已经看到了许多方法,包括

I already saw many approaches, including the ones in this great answer. However, none of them really forces a implementation to return its own type. For example, the following classes would be valid:

class D(id: Int, w: String) extends A(id) {
  type Self = A
  def copy(newId: Int) = new D(newId, w) // returns an A
}

class E(id: Int, v: String) extends A(id) {
  type Self = B
  def copy(newId: Int) = new B(newId, "")
}

如果我正在复制对象的副本,而我仅有的信息是这些对象属于A的给定子类,那么我可以做到这一点:

The fact that I can do that causes that, if I am doing copies of objects of which the only information I have is that they are of a given subclass of A's:

// type error: Seq[A] is not a Seq[CA]!
def createCopies[CA <: A](seq: Seq[CA]): Seq[CA] = seq.map(_.copy(genNewId()))

有没有一种更好的,类型安全的方式可以做到这一点?

Is there a better, type-safe way I can do that?

如果可能的话,我想保留创建抽象类的任意深层次结构的能力.也就是说,在前面的示例中,我期望能够创建扩展了A抽象A2,然后继续创建A2的具体子类.但是,如果这样可以简化问题(例如抽象类型),则无需进一步扩展已经具体的类.

If possible, I would like to keep the ability to create arbitrarily deep hierarchies of abstract classes. That is, in the previous example, I'm expecting to be able to create an abstract class A2 that extends A, and then proceed to create A2's concrete subclasses. However, if that simplifies the problem (as it's the case with abstract types), I do not need to further extend already concrete classes.

推荐答案

我能想到的唯一解决方案是:

The only solution I could think of was this one:

trait CanCopy[T <: CanCopy[T]] { self: T =>
  type Self >: self.type <: T
  def copy(newId: Int): Self
}

abstract class A(id: Int) { self:CanCopy[_] =>
  def copy(newId: Int): Self
}

以下内容将编译:

class B(id: Int, x: String) extends A(id) with CanCopy[B] {
  type Self = B
  def copy(newId: Int) = new B(newId, x)
}

class C(id: Int, y: String, z: String) extends A(id) with CanCopy[C] {
  type Self = C
  def copy(newId: Int) = new C(newId, y, z)
}

以下内容无法编译:

class D(id: Int, w: String) extends A(id) with CanCopy[D] {
  type Self = A
  def copy(newId: Int) = new D(newId, w) // returns an A
}

class E(id: Int, v: String) extends A(id) with CanCopy[E] {
  type Self = B
  def copy(newId: Int) = new B(newId, "")
}

编辑

我实际上忘了删除复制方法.这可能更通用:

Edit

I actually forgot to remove the copy method. This might be a bit more generic:

trait StrictSelf[T <: StrictSelf[T]] { self: T =>
  type Self >: self.type <: T
}

abstract class A(id: Int) { self:StrictSelf[_] =>
  def copy(newId:Int):Self
}

这篇关于Scala:使用具体实例的返回类型实现方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆