0

我有:

trait Pet[T <: Pet[T]] {    //disallows: Dog extends Pet[String]
  self: T =>                //disallows: Dog extends Pet[Monkey]
  def rename(s: String): T
  def name: String
}

现在可以很容易地添加像Feline这样可以扩展Pet类的特征,如下所示:

trait Feline[T <: Feline[T]] extends Pet[T] {
  self: T =>
  def pur : Unit = println("purrrr")
  def scratch: Unit
}

但是,如果我要引入一种Pet与自我类型混合的类型,例如:

trait PetCareInfo[T <: PetCareInfo[T]] {
    self: T with Pet[T] =>
    def registerPet: Unit
  }

我得到错误:

类型参数 [T] 不符合 trait Pet 的类型参数边界 [T <: Pet[T]]

我的理解是,这是因为自我类型检查会单独查看PetCareInfo类型A with B,因此无法满足限制。(不确定这是错误还是功能)

我可以改用存在类型:

type TypeRestriction: Pet[A] forSome {type A}

trait PetCareInfo[T <: PetCareInfo[T]] {
    self: T with TypeRestriction => //mix-in restriction
    def registerPet: Unit
  }

这会有点工作。两个问题:

  1. 我无法在混入限制行直接定义存在类型。我得到:

; 预期但找到了“forSome”。

有没有办法解决这个问题?

  1. 在实践中PetCareInfo'forSome限制 +Pet自己的限制意味着我不能拥有:

    class Cat extends Pet[Dog] with PetCareInfo[Cat]

但我想知道是否有办法不依赖Pet于此。

更新

对于问题 2,我可以将现有的类型限制更改为:

type Restriction[T] = A with Pet[A] forSome {type A <: PetCareInfo[T]}

trait PetCareInfo[T <: PetCareInfo[T]] {
  self: Restriction[T] =>
  def registerPet: Unit
}

这似乎正在解决问题。虽然,仍然不能保证结构A类型与 相同T,所以我们仍然依赖Pet. :(

4

1 回答 1

2

尝试这个:

trait PetCareInfo[T <: Pet[T] with PetCareInfo[T]] {
  self: T =>
  def registerPet: Unit
}

abstract class Cat extends Feline[Cat] with PetCareInfo[Cat] // OK
abstract class Dog extends Pet[Dog] with PetCareInfo[Dog] // OK
abstract class Tiger extends Feline[Tiger] with PetCareInfo[Cat] // Error.

更新:上面演示了一个关系。也就是说,Cat两者都是 a Feline并且是 a PetCareInfo。这是一个使 成为PetCareInfo的成员的替代方法Pet,因此 aCat 具有 PetCareInfo. (我假设这是有道理的。如果这更合适,您同样可以拥有一个Pet成员。)PetCareInfo

// Change of emphasis: T is type of Pet. OK since we're in charge of its definition.
trait PetCareInfo[T <: Pet[T]] {
  // Etc.
}

trait Pet[T <: Pet[T]] {
  // Etc.
  val info: PetCareInfo[T]
}

abstract class Dog extends Pet[Dog] {
  // Etc.
  override val info = new PetCareInfo[Dog] {
     // Define a what a PetCareInfo looks like for a dog.
  }
}

后一种方法也可用于隐藏PetCareInfo(如果info成员是private),以防此类详细信息对代码用户无用。

更新2:顺便说一句,关于错误“ type arguments [T] do not conform to trait Pet's type parameter bounds [T <: Pet[T]]”:

trait PetCareInfo[T <: PetCareInfo[T]] {
  self: T with Pet[T] => // <- Error
  def registerPet: Unit
}

该消息是不言自明的:Pet'sT必须来自Pet[T]; 但是,您只定义了从 派生的Tfor ,并且 a 与 a没有明确的关系。该声明仅限制任何具体实例的类型,不能用于更改 a 所代表的定义。PetCareInfoPetCareInfo[T]PetCareInfo[T]Pet[T]selfPetCareInfoT

也就是说,T必须派生自PetCareInfo[T]并且self必须属于扩展的对象T with a Pet[T]。但是,由于T不是从 派生的Pet[T],因此不可能创建这样的实例,因此会出现错误。因此,这不是错误,而是必不可少的类型检查。

于 2017-10-09T12:05:08.977 回答