Scala:限制特征混入 f 有界多态特征
Scala: Restricting traits mixing-in f-bounded polymorphic traits
我有:
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
class 的特征可以很容易地添加如下:
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
}
我收到错误:
type arguments [T] do not conform to trait Pet's type parameter bounds [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
}
这还挺管用的。两个问题:
- 我无法在混入限制行直接定义存在类型。我得到:
; expected but 'forSome' found.
有办法解决这个问题吗?
实际上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
。 :(
试试这个:
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.
Update:上面演示了一个is a的关系。也就是说,Cat
都是是Feline
,是PetCareInfo
。这是使 PetCareInfo
成为 Pet
成员的替代方法,因此 Cat
具有 PetCareInfo
。 (我假设这是有道理的。如果更合适的话,您同样可以拥有 PetCareInfo
的 Pet
成员。)
// 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
的 T
必须派生自 Pet[T]
;然而,您只为 PetCareInfo
定义了一个 T
派生自 PetCareInfo[T]
,而 PetCareInfo[T]
与 Pet[T]
没有明确的关系。 self
声明仅限制任何具体 PetCareInfo
实例的类型,不能用于更改 T
表示的定义。
也就是说,T
必须派生自 PetCareInfo[T]
,而 self
必须属于扩展 T with a Pet[T]
的对象。但是,由于 T
不是从 Pet[T]
派生的,因此不可能创建这样的实例,因此会出现错误。所以,这不是错误,而是必要的类型检查。
我有:
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
class 的特征可以很容易地添加如下:
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
}
我收到错误:
type arguments [T] do not conform to trait Pet's type parameter bounds [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
}
这还挺管用的。两个问题:
- 我无法在混入限制行直接定义存在类型。我得到:
; expected but 'forSome' found.
有办法解决这个问题吗?
实际上
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
。 :(
试试这个:
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.
Update:上面演示了一个is a的关系。也就是说,Cat
都是是Feline
,是PetCareInfo
。这是使 PetCareInfo
成为 Pet
成员的替代方法,因此 Cat
具有 PetCareInfo
。 (我假设这是有道理的。如果更合适的话,您同样可以拥有 PetCareInfo
的 Pet
成员。)
// 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
的 T
必须派生自 Pet[T]
;然而,您只为 PetCareInfo
定义了一个 T
派生自 PetCareInfo[T]
,而 PetCareInfo[T]
与 Pet[T]
没有明确的关系。 self
声明仅限制任何具体 PetCareInfo
实例的类型,不能用于更改 T
表示的定义。
也就是说,T
必须派生自 PetCareInfo[T]
,而 self
必须属于扩展 T with a Pet[T]
的对象。但是,由于 T
不是从 Pet[T]
派生的,因此不可能创建这样的实例,因此会出现错误。所以,这不是错误,而是必要的类型检查。