Scala:在 parent 方法中维护 child class?
Scala: Maintain child class in parent methods?
当你有parent时:
abstract class Parent {
def something(arg: ???): Parent = ???
}
和
class Child extends Parent {}
我愿意
val updatedChild = new Child().something(...)
updatedChild
是 Child
类型而不是 Parent
类型,这可能吗?
看来你可以做到:
class Parent[THIS <: Parent[THIS]] {
def something: THIS
}
这似乎行得通。
我不确定这是否是您应该做的事情。
一种方法是参数化父级:
abstract class Parent[T <: Parent[T]] {
def something(arg: Foo): T
}
class Child(val foo: String) extends Parent[Child] {
def something(arg: String) = return new Child(arg)
}
有时,您也可以使用 this.type
:
class Parent {
def something(arg: Foo): this.type = this
}
class Child {
override def something(arg: Foo) = this
}
但是后一种方法只有在你想要 return 是 this
时才有效(this.type
不是 Parent
或 Child
,而是只有一个实例的特定类型 - this
).
这里建议实际编译:
abstract class Parent[Repr <: Parent[Repr]] {
def something(arg: Int): Repr
}
这是您可以做的事情,至少没有明确反对。标准集合库经常使用它,例如参见IterableLike 作为这种 F 界多态性的典型例子。
Andrey 和 Dima 的回答都涵盖了一种仅使用面向对象模式来解决问题的方法。
但是我想指出另一种方法叫做 typeclasses (在函数式语言中更常见), 如果您打算使用您的界面编写通用函数,这将很有帮助。
首先,您没有父级 class,而是拥有一个 接口,它描述了可以在类型 class 的实例上执行的操作.
trait Typeclass[T] {
def something(t: T)(arg: Foo): T
}
然后,您将定义您的类型,这次它们不扩展任何父级 class,因此它们不必重写任何内容。
class Child {
...
}
现在,您必须证明您的类型是 class.
类型的一个实例
(一个常见的地方是在 class 的伴生对象中).
object Child {
implicit final val ChildTypeclass: Typeclass[Child] = new Typeclass[Child] {
override def something(child: Child)(arg: Foo): Child = ???
}
}
最后,您定义了一个泛型方法,它可以对任何类型 T 进行操作,只要该类型存在您的类型的实例class。
def generic[T](t: T, arg: Foo)(implicit tt: Typeclass[T]): T =
tt.something(t)(arg)
奖金,如果你想恢复 "dot notation" 你可以在你的类型中添加一个 Ops 模式class。
object syntax {
object typeclass {
implicit final class TypeclassOps[T](val t: T) extends AnyVal {
final def something(arg: Foo)(implicit tt: Typelcass[T]) =
tt.something(t)(arg)
}
}
}
import syntax.typeclasss._
def generic[T: Typelcass](t: T, arg: Foo): T
t.something(arg)
val newChild = generic(new Child, new Foo)
// newChild: Child = ???
此外,一种常见的方法是在 class 中定义 something
方法,然后类型 class 实例将调用转发到 class 中定义的方法,这样你就可以在 Child
的任何实例中使用你的方法,而不必将所有类型 class 机器。
我必须说这对于非常高级的抽象非常有用,您计划为其提供许多类型的实例(甚至是您无法控制的类型,如任何标准集合类型) 并编写可以对其中任何一个进行操作的非常通用的函数。
如果不是,F 有界类型似乎是更合理的解决方案。
当你有parent时:
abstract class Parent {
def something(arg: ???): Parent = ???
}
和
class Child extends Parent {}
我愿意
val updatedChild = new Child().something(...)
updatedChild
是 Child
类型而不是 Parent
类型,这可能吗?
看来你可以做到:
class Parent[THIS <: Parent[THIS]] {
def something: THIS
}
这似乎行得通。
我不确定这是否是您应该做的事情。
一种方法是参数化父级:
abstract class Parent[T <: Parent[T]] {
def something(arg: Foo): T
}
class Child(val foo: String) extends Parent[Child] {
def something(arg: String) = return new Child(arg)
}
有时,您也可以使用 this.type
:
class Parent {
def something(arg: Foo): this.type = this
}
class Child {
override def something(arg: Foo) = this
}
但是后一种方法只有在你想要 return 是 this
时才有效(this.type
不是 Parent
或 Child
,而是只有一个实例的特定类型 - this
).
这里建议实际编译:
abstract class Parent[Repr <: Parent[Repr]] {
def something(arg: Int): Repr
}
这是您可以做的事情,至少没有明确反对。标准集合库经常使用它,例如参见IterableLike 作为这种 F 界多态性的典型例子。
Andrey 和 Dima 的回答都涵盖了一种仅使用面向对象模式来解决问题的方法。
但是我想指出另一种方法叫做 typeclasses (在函数式语言中更常见), 如果您打算使用您的界面编写通用函数,这将很有帮助。
首先,您没有父级 class,而是拥有一个 接口,它描述了可以在类型 class 的实例上执行的操作.
trait Typeclass[T] {
def something(t: T)(arg: Foo): T
}
然后,您将定义您的类型,这次它们不扩展任何父级 class,因此它们不必重写任何内容。
class Child {
...
}
现在,您必须证明您的类型是 class.
类型的一个实例
(一个常见的地方是在 class 的伴生对象中).
object Child {
implicit final val ChildTypeclass: Typeclass[Child] = new Typeclass[Child] {
override def something(child: Child)(arg: Foo): Child = ???
}
}
最后,您定义了一个泛型方法,它可以对任何类型 T 进行操作,只要该类型存在您的类型的实例class。
def generic[T](t: T, arg: Foo)(implicit tt: Typeclass[T]): T =
tt.something(t)(arg)
奖金,如果你想恢复 "dot notation" 你可以在你的类型中添加一个 Ops 模式class。
object syntax {
object typeclass {
implicit final class TypeclassOps[T](val t: T) extends AnyVal {
final def something(arg: Foo)(implicit tt: Typelcass[T]) =
tt.something(t)(arg)
}
}
}
import syntax.typeclasss._
def generic[T: Typelcass](t: T, arg: Foo): T
t.something(arg)
val newChild = generic(new Child, new Foo)
// newChild: Child = ???
此外,一种常见的方法是在 class 中定义 something
方法,然后类型 class 实例将调用转发到 class 中定义的方法,这样你就可以在 Child
的任何实例中使用你的方法,而不必将所有类型 class 机器。
我必须说这对于非常高级的抽象非常有用,您计划为其提供许多类型的实例(甚至是您无法控制的类型,如任何标准集合类型) 并编写可以对其中任何一个进行操作的非常通用的函数。
如果不是,F 有界类型似乎是更合理的解决方案。