类型检查器认为接口的此类要求IBase
是循环的:
<?hh // strict
interface IBase {
require extends Derived;
}
class Derived implements IBase {}
// Cyclic class definition : IBase Derived (Typing[4013])
据我了解,约束只是阻止所有后代implements IBase
没有extends Derived
. 有没有我没看到的漏洞?
我为什么在乎?
我对想要与自身或其子类型的其他实例进行比较的接口感兴趣。
<?hh // strict
interface Comparable<-T as Comparable<T>> {
require extends ArtificialCeiling;
public function compare(T $comparee): bool;
}
abstract class ArtificialCeiling implements Comparable<ArtificialCeiling> {
abstract public function compare(ArtificialCeiling $comparee): bool;
}
(this
不是这里的答案,因为this
在逆变位置不是声音,尤其是在接口中)
假设现在我们想要接受并存储一个包装器,Comparable
但我们并不关心Comparable
它拖着什么类型。通常,我们只需使用上限参数化,或者mixed
如果它不受约束。
问题是上限Comparable
是Comparable<Comparable<Comparable<...
永远的,但我没有精力永远输入它。如果没有像 Scala 这样的存在类型或像 那样的多重约束TComparable as Comparable & ArtificialCeiling
,我们不得不求助于一些不太明显的东西。require extends ArtificialCeiling
就像多重约束一样,如果没有这个神秘的循环问题,这将是一个很好的解决方案。
另一种自然的选择是接受类将参数附加到它自己的参数列表中TComparable as Comparable<TComparable>
,但这违背了不关心的原则TComparable
。