在 Scala 中扩展特征时如何创建新的特定类型 class
How can I create a new specific type of class when extending a trait in scala
我有一个特点,其中(除其他外)我想要一个方法来创建 class 的新实例,然后还有其他方法使用 [=45= 的那个实例].
我的代码的一个非常简化的版本是:
trait A {
def prev: A
def get(end: A): A
}
class B extends A {
def prev: B = new B()
def get(end: B): B = end.prev
}
我想在这里展示的是 next 将 return class 的一个新实例(实际上有一些新的构造函数参数)并且 get 方法将使用 next内部(连同其他逻辑)
上面的问题是编译器说"class B must implement abstract member get(end: A): A",这是合理的。
我尝试使用类型边界来解决它:
trait A {
def prev: A
def get(end: A): A
}
case class B extends A {
def prev[TX <: A]: TX = new B()
def get[TX <: A](end: TX): TX = end.prev
}
但现在 new B()
上的错误是 "Expression of type B doesn't conform to expected type TX",end.prev
上的错误是 "Expression of type A doesn't conform to expected type TX"
我不明白为什么这是个问题,因为下一个是 returning B,它是 A 的子类型,也就是 TX。
有没有办法实现我想在这里做的事情?
一些上下文,以防以上所有内容看起来过于抽象。我正在实现一个循环双向链表,因为我找不到类似的东西。特征包括:
trait Circular[T] {
// Nodes in the list from the current position up to but NOT INCLUDING the end
def toStream(end: Circular[T]): Stream[Circular[T]]
def prev: Circular[T]
...
我的 class 看起来像:
case class Node[T](val data: T, var prev: Node[T], var next: Node[T])
case class CircularList[T](first: Node[T], last: Node[T], current: Node[T])
extends Circular[T] {
// Nodes in the list from the current position up to but not including the end
def toStream(end: CircularList[T]): Stream[CircularList[T]] = {
@tailrec
def toStreamRec(end: CircularList[T], acc: Stream[CircularList[T]]): Stream[CircularList[T]] = {
if (this == end) {
acc
} else {
toStreamRec(end.prev, Stream.cons(end.prev, acc))
}
}
toStreamRec(end, Stream.empty)
}
def prev: CircularList[T] = new CircularList[T](first, last, current.prev)
...
所以 toStream
在我的缩减示例中映射到 get
。
你想要的是一个叫做F-bound generic的东西。代码如下:
trait Base[T <: Base[T]] {
def next: T
def get(end: T): T
}
class Chlid extends Base[Child] {
def next: Chlid = new Chlid()
def get(end: Chlid): Chlid = end.next
}
您的代码无法编译,因为
def get(end: B): B
不是
的覆盖
def get(end: A): A
因为原始方法接受 A
类型的对象,而您的方法只需要更窄的类型 B
对于您的 Circular
示例,您需要
trait Circular[T, C <: Circular[T, C]] {
// Nodes in the list from the current position up to but NOT INCLUDING the end
def toStream(end: C): Stream[C]
def next: C
}
case class Node[T](val data: T, var prev: Node[T], var next: Node[T])
case class CircularList[T](first: Node[T], last: Node[T], current: Node[T]) extends Circular[T, CircularList[T]] {
// Nodes in the list from the current position up to but not including the end
def toStream(end: CircularList[T]): Stream[CircularList[T]] = {
@tailrec
def toStreamRec(end: CircularList[T], acc: Stream[CircularList[T]]): Stream[CircularList[T]] = {
if (this == end) {
acc
} else {
toStreamRec(end.prev, Stream.cons(end.prev, acc))
}
}
toStreamRec(end, Stream.empty)
}
def prev: CircularList[T] = new CircularList[T](first, last, current.prev)
override def next: CircularList[T] = ???
}
我有一个特点,其中(除其他外)我想要一个方法来创建 class 的新实例,然后还有其他方法使用 [=45= 的那个实例].
我的代码的一个非常简化的版本是:
trait A {
def prev: A
def get(end: A): A
}
class B extends A {
def prev: B = new B()
def get(end: B): B = end.prev
}
我想在这里展示的是 next 将 return class 的一个新实例(实际上有一些新的构造函数参数)并且 get 方法将使用 next内部(连同其他逻辑)
上面的问题是编译器说"class B must implement abstract member get(end: A): A",这是合理的。
我尝试使用类型边界来解决它:
trait A {
def prev: A
def get(end: A): A
}
case class B extends A {
def prev[TX <: A]: TX = new B()
def get[TX <: A](end: TX): TX = end.prev
}
但现在 new B()
上的错误是 "Expression of type B doesn't conform to expected type TX",end.prev
我不明白为什么这是个问题,因为下一个是 returning B,它是 A 的子类型,也就是 TX。
有没有办法实现我想在这里做的事情?
一些上下文,以防以上所有内容看起来过于抽象。我正在实现一个循环双向链表,因为我找不到类似的东西。特征包括:
trait Circular[T] {
// Nodes in the list from the current position up to but NOT INCLUDING the end
def toStream(end: Circular[T]): Stream[Circular[T]]
def prev: Circular[T]
...
我的 class 看起来像:
case class Node[T](val data: T, var prev: Node[T], var next: Node[T])
case class CircularList[T](first: Node[T], last: Node[T], current: Node[T])
extends Circular[T] {
// Nodes in the list from the current position up to but not including the end
def toStream(end: CircularList[T]): Stream[CircularList[T]] = {
@tailrec
def toStreamRec(end: CircularList[T], acc: Stream[CircularList[T]]): Stream[CircularList[T]] = {
if (this == end) {
acc
} else {
toStreamRec(end.prev, Stream.cons(end.prev, acc))
}
}
toStreamRec(end, Stream.empty)
}
def prev: CircularList[T] = new CircularList[T](first, last, current.prev)
...
所以 toStream
在我的缩减示例中映射到 get
。
你想要的是一个叫做F-bound generic的东西。代码如下:
trait Base[T <: Base[T]] {
def next: T
def get(end: T): T
}
class Chlid extends Base[Child] {
def next: Chlid = new Chlid()
def get(end: Chlid): Chlid = end.next
}
您的代码无法编译,因为
def get(end: B): B
不是
的覆盖def get(end: A): A
因为原始方法接受 A
类型的对象,而您的方法只需要更窄的类型 B
对于您的 Circular
示例,您需要
trait Circular[T, C <: Circular[T, C]] {
// Nodes in the list from the current position up to but NOT INCLUDING the end
def toStream(end: C): Stream[C]
def next: C
}
case class Node[T](val data: T, var prev: Node[T], var next: Node[T])
case class CircularList[T](first: Node[T], last: Node[T], current: Node[T]) extends Circular[T, CircularList[T]] {
// Nodes in the list from the current position up to but not including the end
def toStream(end: CircularList[T]): Stream[CircularList[T]] = {
@tailrec
def toStreamRec(end: CircularList[T], acc: Stream[CircularList[T]]): Stream[CircularList[T]] = {
if (this == end) {
acc
} else {
toStreamRec(end.prev, Stream.cons(end.prev, acc))
}
}
toStreamRec(end, Stream.empty)
}
def prev: CircularList[T] = new CircularList[T](first, last, current.prev)
override def next: CircularList[T] = ???
}