具有通用自我类型的 Scala 特征

问题描述 投票:0回答:5

我有一个特征,它定义了一个动作,它是 .copy() 的美化版本。看起来像这样:

trait Optimize[T] {
    def optimize: T
}

以及一堆扩展它的类,例如:

case class Account(field: String) extends Optimize[Account] {
    def optimize = this.copy(field = field.intern())
}

有没有一种方法可以定义一个特征,要求方法优化返回与 self 相同的类型,但在扩展它时不需要指定类型?这样我就可以写:

case class Account(field: String) extends Optimize {
    def optimize = this.copy(field = field.intern())
}
scala generics
5个回答
3
投票

您可以使用

this.type
作为返回值来引用实现者的类型。

def optimize: this.type = ???

2
投票

简短回答:你不能。

无论怎样(抽象类型),您需要告诉

Optimize
该函数的返回类型是什么。

为什么?因为

Optimize
可以在类型表达式中使用而无需指定具体类,并且编译器无法知道它将生成什么类型:

def someOtherMethod (a: Optimize) {
  val result = a.optimize // what is the type?
}

(在抽象类型的情况下,返回类型将是

a.T
Optimize#T
...不是很有用)


1
投票

如果您只想避免在扩展时指定类型参数,则可以将定义移至类型成员,如下所示。

trait Optimize {
    type T
    def optimize: T
}

case class Account(field: String) extends Optimize {
    type T = Account
    def optimize = this.copy(field = field.intern())
}

但是您只是将其从一个地方移到了另一个地方。此外,使用类型参数参数化特征比让类型成员参与要好得多。

这样做的原因是什么?因为您的用例对于类型参数来说似乎是完全有效的情况。需要通过类型参数或类型成员告诉 Trait 优化()返回的是什么。


0
投票

有这样的事吗?

trait Ret[T]

trait A {
  def func(): Ret[_ <: A]
}

case class B() extends A {
  override def func(): Ret[B] = ???
}


0
投票

除了阿尔瓦罗所说的之外,我认为你的特质的一个问题是没有什么可以阻止一个人这样做:

case class Account(field: String) extends Optimize[Int] {
    def optimize: Int = 42
}

您可能不打算允许这一点。为了防止这种情况,我认为你必须这样做:

trait Optimize[T <: Optimize[T]] {
    def optimize: T
}

这确保了一个类只能扩展自身的

Optimize

© www.soinside.com 2019 - 2024. All rights reserved.