Generics &引用;MyType“;问题:我是否必须在Scala中使用抽象类型(或泛型)来返回实际的类?
我不确定是否有更好的方法:Generics &引用;MyType“;问题:我是否必须在Scala中使用抽象类型(或泛型)来返回实际的类?,generics,scala,Generics,Scala,我不确定是否有更好的方法: trait Animal { val name: String val weight: Int type SubAnimal <: Animal def updateName(n: String) = returnMe(n, this.weight) def updateWeight(w: Int) = returnMe(this.name, w) // Abstract protected method protected de
trait Animal {
val name: String
val weight: Int
type SubAnimal <: Animal
def updateName(n: String) = returnMe(n, this.weight)
def updateWeight(w: Int) = returnMe(this.name, w)
// Abstract protected method
protected def returnMe(n: String, w: Int): SubAnimal
}
case class Dog(name: String, weight: Int) extends Animal {
type SubAnimal = Dog
override def returnMe(n: String, w: Int): Dog = Dog("Dog: " + name, w)
}
case class Cat(name: String, weight: Int) extends Animal {
type SubAnimal = Cat
override def returnMe(n: String, w: Int): Cat = Cat("Cat: " + name, w)
}
val fido = Dog("Fido", 11)
println( fido )
val fido2 = fido.updateWeight(12)
println( fido2 )
我想在调用updateName
或updateView
后返回问题动物的实际类型(即非animal
)。我知道如果我直接重写updateName
和updateView
,那么将返回正确的类型,并且我不必使用抽象类型SubAnimal
对于抽象类型的值与子类的值相同的特殊情况,是否有一些巧妙的方法来转义抽象类型
(这就是所谓的“MyType”问题)。使用类型参数化
trait Animal[A <: Animal[A]] {
val name: String
val weight: Int
def updateName(n: String) = returnMe(n, this.weight)
def updateWeight(w: Int) = returnMe(this.name, w)
// Abstract protected method
protected def returnMe(n: String, w: Int): A
}
case class Dog(name: String, weight: Int) extends Animal[Dog] {
override def returnMe(n: String, w: Int) = Dog("Dog: " + name, w)
}
case class Cat(name: String, weight: Int) extends Animal[Cat] {
override def returnMe(n: String, w: Int) = Cat("Cat: " + name, w)
}
trait Animal[A关于这个主题的一些人……您所寻找的通常被称为“MyType”,它的典型Scala/Java编码使用递归类型参数:
public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable {
public final int compareTo(E o)
// ...
}
公共抽象类Enum实现可比较的、可序列化的{
公共最终国际比较(E/o)
// ...
}
这应该可以:
trait Animal[T] {
self:T =>
val name: String
val weight: Int
def updateName(n: String): T = returnMe(n, this.weight)
def updateWeight(w: Int): T = returnMe(this.name, w)
// Abstract protected method
protected def returnMe(n: String, w: Int): T
}
case class Dog(name: String, weight: Int) extends Animal[Dog] {
override def returnMe(n: String, w: Int): Dog = Dog("Dog: " + name, w)
}
case class Cat(name: String, weight: Int) extends Animal[Cat] {
override def returnMe(n: String, w: Int): Cat = Cat("Cat: " + name, w)
}
<> >像 case类CAT(name:String,Bug:int)扩展了动物[狗] /代码>被编译器拒绝。从 HMM中修改的代码被盗。您的解决方案大概是“抽象类型”的意思。我认为“类型参数化”和“抽象类型”一样坏/好。在这种情况下。你同意吗?@olle:我从来都不理解抽象类型成员的意义,也从来没有在我自己的代码中使用过它们。我认为它们是语言中不必要的冗余。(Paul P最近在邮件列表中表达了类似的想法。)你是对的,抽象类型似乎是纯粹的糖。但我非常喜欢它们,因为我认为更容易考虑“类型字段”您可以在子类中重写它,而不是相应的类型参数语法。抽象类型不仅仅是语法上的糖。虽然您通常可以将抽象类型版本转换为泛型版本,反之亦然,但它们并不等价:如果您有Foo[X],则像Foo[Int]这样的每个实例化都会建立一个新类型。如果您有Foo{type X},只有一个Foo类型,它恰好包含一个抽象类型变量。因此,神奇的方法是使用“this.type”(从您的链接),但由于我返回了一个新实例(不是this)那么这是不可能的。在后面的文章中,奥德斯基推荐了这个问题的抽象类型,所以我想讨论到此结束。谢谢。是的,this.type太窄了,不能充当MyType:它是这个类型,但没有这个类的其他实例。嗨@Landei,我看不出这和@one-zero-one提供的解决方案之间有什么区别。为什么需要self:T=>部分?当我把它拿走时,我得到了相同的输出。@olle:行为与一零一的解决方案相同,只是更容易阅读。没有self:T部分,您可以编写case类Cat(name:String,weight:Int)扩展Animal[Int]
,这显然是不允许的。有关详细信息,请参阅我提供的链接。
trait Animal[T] {
self:T =>
val name: String
val weight: Int
def updateName(n: String): T = returnMe(n, this.weight)
def updateWeight(w: Int): T = returnMe(this.name, w)
// Abstract protected method
protected def returnMe(n: String, w: Int): T
}
case class Dog(name: String, weight: Int) extends Animal[Dog] {
override def returnMe(n: String, w: Int): Dog = Dog("Dog: " + name, w)
}
case class Cat(name: String, weight: Int) extends Animal[Cat] {
override def returnMe(n: String, w: Int): Cat = Cat("Cat: " + name, w)
}