Scala中如何让Entity特质的withId返回子类对应的IdAnd类型?
问题解决方法
问题根源在于Animal直接继承Entity[Animal],导致Cat实例的withId方法继承自Animal的定义,返回类型被固定为IdAnd[Animal],而非具体子类Cat对应的IdAnd[Cat]。以下是两种可行的修改方案:
方案一:让父特质支持子类自绑定泛型
// Generic trait to represent a class with its own type of ID trait Entity[T <: Entity[T]] { self: T => type ID final def withId(id: T#ID): IdAnd[T] = IdAnd(id, self) } case class IdAnd[T <: Entity[T]](id: T#ID, entity: T) // 将Animal改为泛型特质,要求子类传入自身类型作为参数 sealed trait Animal[A <: Animal[A]] extends Entity[A] { override type ID = Long } // Cat继承时指定自身为泛型参数 case class Cat(name: String) extends Animal[Cat] object Animal { val test: IdAnd[Cat] = Cat("Garfield").withId(1L) // 现在可正常编译 }
通过让Animal成为泛型特质,强制子类在继承时绑定自身类型,Entity的泛型参数T会被解析为具体子类(如Cat),withId方法的返回类型也就对应为IdAnd[Cat]。
方案二:使用this.type指代具体实例类型
trait Entity { type ID final def withId(id: ID): IdAnd[this.type] = IdAnd(id, this) } // 调整IdAnd的泛型约束,兼容任意Entity子类 case class IdAnd[T <: Entity](id: T#ID, entity: T) sealed trait Animal extends Entity { override type ID = Long } case class Cat(name: String) extends Animal object Animal { val test: IdAnd[Cat] = Cat("Garfield").withId(1L) // 编译正常 }
该方案移除了Entity的F-bounded泛型,改用this.type直接指代当前实例的具体类型,同时放宽IdAnd的泛型约束,使其能接受任意Entity子类。这样Cat实例调用withId时,返回类型会自动匹配为IdAnd[Cat]。
内容的提问来源于stack exchange,提问作者Maxence Cramet
相关产品推荐
相关产品推荐

