类型检查器认为接口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
在逆变位置不发声,especially in interfaces)
假设现在我们想要接受并存储 Comparable
的包装,但我们并不关心它在Comparable
的哪种类型。通常情况下,我们只是使用上限进行参数化,如果不受约束,则为mixed
。
问题在于Comparable
的上限永远是Comparable<Comparable<Comparable<...
,但是我没有足够的耐力为永恒打字。如果没有像Scala这样的存在类型或像TComparable as Comparable & ArtificialCeiling
这样的多个约束,我们就必须采用不太明显的东西。 require extends ArtificialCeiling
就像一个多重约束,没有这个神秘的循环问题,它将是一个整洁的修复。
另一个自然的替代方法是让接受类将参数作为TComparable as Comparable<TComparable>
附加到自己的参数列表中,但这违背了不关心TComparable
的原则。
答案 0 :(得分:1)
嗯,我不是专家,但这个消息对我来说似乎很清楚:
该定义是循环的,因为Derived
使用IBase
和IBase
引用Derived
。
根据{{3}}:
要求延伸应按字面意思。班级必须扩展 必修课;因此,实际所需的课程不符合要求 需求。这是为了避免一些微妙的循环依赖 检查要求。
我认为要采用的方法是指定祖先类的要求,并在非抽象派生类中实现接口。或者也许只是在祖先类中实现compare
作为普通方法,而不是使用特征。