sách gpt4 ai đã đi

scala - 如何使用 Scala 的 this 类型、抽象类型等来实现 Self 类型?

In lại 作者:行者123 更新时间:2023-12-01 01:06:38 27 4
mua khóa gpt4 Nike

我无法在任何其他问题中找到答案。假设我有一个抽象父类(super class) Abstract0,它有两个子类 Concrete1 和 Concrete1。我希望能够在 Abstract0 中定义类似

def setOption(...): Self = {...}

其中 Self 将是具体的子类型。这将允许像这样对 setOption 进行链接调用:
val obj = new Concrete1.setOption(...).setOption(...)

并且仍然得到 Concrete1 作为 obj 的推断类型。

我不想要的是定义这个:
abstract class Abstract0[T <: Abstract0[T]]

因为它使客户更难处理这种类型。我尝试了各种可能性,包括抽象类型:
abstract class Abstract0 {
type Self <: Abstract0
}

class Concrete1 extends Abstract0 {
type Self = Concrete1
}

但是这样就不可能实现 setOption,因为 cái này在 Abstract0 中没有 Self 类型。并使用 this: Self =>在 Abstract0 中也不起作用。

这个问题有哪些解决方案?

1 Câu trả lời

这是什么this.type是为了:

scala> abstract class Abstract0 {
| def setOption(j: Int): this.type
| }
defined class Abstract0

scala> class Concrete0 extends Abstract0 {
| var i: Int = 0
| def setOption(j: Int) = {i = j; this}
| }
defined class Concrete0

scala> (new Concrete0).setOption(1).setOption(1)
res72: Concrete0 = Concrete0@a50ea1

如您所见,setOption 返回使用的实际类型,而不是 Abstract0。如果 Concrete0 有 setOtherOptionSau đó (new Concrete0).setOption(1).setOtherOption(...)会工作

更新:在评论中回答 JPP 的后续问题(如何返回新实例:
问题中描述的一般方法是正确的(使用抽象类型)。但是,对于每个子类,新实例的创建都需要明确。

一种方法是:
abstract class Abstract0 {
type Self <: Abstract0

var i = 0

def copy(i: Int) : Self

def setOption(j: Int): Self = copy(j)
}

class Concrete0(i: Int) extends Abstract0 {
type Self = Concrete0
def copy(i: Int) = new Concrete0(i)
}

另一种方法是遵循 Scala 集合库中使用的构建器模式。也就是说, setOption 接收一个隐式构建器参数。这样做的优点是可以使用更多方法来构建新实例,而不仅仅是“复制”,并且可以完成复杂的构建。例如。 setSpecialOption 可以指定返回实例必须是 SpecialConcrete。

这是解决方案的说明:
trait Abstract0Builder[To] {
def setOption(j: Int)
def result: To
}

trait CanBuildAbstract0[From, To] {
def apply(from: From): Abstract0Builder[To]
}


abstract class Abstract0 {
type Self <: Abstract0

def self = this.asInstanceOf[Self]

def setOption[To <: Abstract0](j: Int)(implicit cbf: CanBuildAbstract0[Self, To]): To = {
val builder = cbf(self)
builder.setOption(j)
builder.result
}

}

class Concrete0(i: Int) extends Abstract0 {
type Self = Concrete0
}

object Concrete0 {
implicit def cbf = new CanBuildAbstract0[Concrete0, Concrete0] {
def apply(from: Concrete0) = new Abstract0Builder[Concrete0] {
var i = 0
def setOption(j: Int) = i = j
def result = new Concrete0(i)
}
}
}

object Main {
def main(args: Array[String]) {
val c = new Concrete0(0).setOption(1)
println("c is " + c.getClass)
}
}

更新 2:
回复 JPP 的第二条评论。在多层嵌套的情况下,使用类型参数代替类型成员并使 Abstract0 成为特征:
trait Abstract0[+Self <: Abstract0[_]] {
// ...
}

class Concrete0 extends Abstract0[Concrete0] {
// ....
}

class RefinedConcrete0 extends Concrete0 with Abstract0[RefinedConcrete0] {
// ....
}

关于scala - 如何使用 Scala 的 this 类型、抽象类型等来实现 Self 类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4313139/

27 4 0
Bài viết được đề xuất: python - 如何避免在 python 2.7 中使用全局?
Bài viết được đề xuất: div 上的 jQuery 类增量
Bài viết được đề xuất: 具有不同值类型的 Python3 输入
Bài viết được đề xuất: jquery - 是否可以通过这种方式乘以输入框的值?
行者123
Hồ sơ cá nhân

Tôi là một lập trình viên xuất sắc, rất giỏi!

Nhận phiếu giảm giá Didi Taxi miễn phí
Mã giảm giá Didi Taxi
Giấy chứng nhận ICP Bắc Kinh số 000000
Hợp tác quảng cáo: 1813099741@qq.com 6ren.com