0

类型检查器认为接口的此类要求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如果它不受约束。

问题是上限ComparableComparable<Comparable<Comparable<...永远的,但我没有精力永远输入它。如果没有像 Scala 这样的存在类型或像 那样的多重约束TComparable as Comparable & ArtificialCeiling,我们不得不求助于一些不太明显的东西。require extends ArtificialCeiling就像多重约束一样,如果没有这个神秘的循环问题,这将是一个很好的解决方案。

另一种自然的选择是接受类将参数附加到它自己的参数列表中TComparable as Comparable<TComparable>,但这违背了不关心的原则TComparable

4

1 回答 1

1

好吧,我不是专家,但信息对我来说似乎很清楚:定义是循环的,因为DerivedusesIBaseIBasereferences Derived。根据文档

require extends 应该按字面意思理解。该类必须扩展所需的类;因此实际所需的类不符合该要求。这是为了在检查需求时避免一些微妙的循环依赖。

我认为要走的路是指定祖先类的要求,并在非抽象派生类中实现接口。或者可能只是compare在祖先类中实现为普通方法,而不是使用特征。

于 2017-10-13T10:38:29.903 回答