我理解为,
Foo
要求它的每个子类型都是
Bar
的子类型。
不是这样的。
def test[T <: Foo]: Unit = {
implicitly[T <:< Bar]
}
我定义了一个
Foo
的子类型,即
T
,它不是
Bar
的子类型。对于子类也是如此。
class Impl extends Foo with Bar
如果一个类扩展了
Foo
,那么它也必须扩展
Bar
。
类型和类是不同的。子类型和子类也是不同的。子类型化和继承也是不同的。
在...
trait Foo { self: Bar => }
Foo
不是Bar
的子类型。因此,您不能将类型为Foo
的值分配给类型为Bar
的变量。
def x: Foo = ???
val y: Bar = x // doesn't compile
如果你想让
Foo
成为
Bar
的子类型,你应该使用继承。
trait Foo extends Bar
def x: Foo = ???
val y: Bar = x // compiles
或子类型化
type Foo <: Bar
def x: Foo = ???
val y: Bar = x // compiles
例如,使用self-types,您可以定义循环依赖关系:
trait Bar { self: Foo => }
trait Foo { self: Bar => }
class Impl extends Foo with Bar
如果
trait A { self: B => }
意味着
A <: B
,那么在这种情况下,我们将拥有
Bar <: Foo
和
Foo <: Bar
,因此
Bar =:= Foo
,但事实并非如此,这些特质的类型是不同的。
trait A { self: B => }
可能意味着
A <: B
(在这种情况下,我们将没有循环依赖项或这些特质将具有相等的类型),但这并非必要:如果您需要
A <: B
,则可以声明
A extends B
,而
trait A { self: B => }
具有不同的含义:所有
A
的子类(而不是子类型)都是
B
的子类型。
或者您可以限制实现。
trait Foo { self: Impl => }
class Impl extends Foo
(Impl
可以是特质Foo
的唯一实现,就像将Foo
与唯一的继承者sealed
一样)但是没有必要使Foo
和Impl
的类型相同。
让我们再考虑以下示例
trait NatHelper {
}
sealed trait Nat { self: NatHelper =>
type Add[M <: Nat] <: Nat
}
object Zero extends Nat with NatHelper {
override type Add[M <: Nat] = M
}
class Succ[N <: Nat] extends Nat with NatHelper {
override type Add[M <: Nat] = Succ[N#Add[M]]
}
请注意,抽象类型
Nat#Add[M]
是
Nat
的子类型,但不需要将其作为
NatHelper
的子类型。
类型不一定与运行时内容相关联。类型可以具有独立的含义。例如,它们可以用于类型级编程,当您用类型来表达业务逻辑时。
此外,还有所谓的标记类型(或幻影类型),当您将一些信息附加到类型时。
val x: Int with Foo = 1.asInstanceOf[Int with Foo]
这里我们将"信息" Foo
附加到数字 1
上。在运行时,它仍然是相同的数字 1
,但在编译时,它被丰富了 "信息" Foo
。然后 x.isInstanceOf[Bar]
返回 false
。我不确定你是否接受此示例,因为我们使用了 asInstanceOf
,但重点是您可以使用某些库函数。
val x: Int with Foo = 1.attach[Foo]
而你将不会知道它在幕后使用了asInstanceOf
(常常发生的情况),你只会信任它返回了Int with Foo
的签名。
sealed trait Foo; object A extends Foo with Bar; object B extends Foo with Bar
中,你也会认为“Foo”必须是“Bar”的子类型吗? - Jasper-M