W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
Hack支持通用協(xié)方差和逆變。這是一個(gè)相當(dāng)先進(jìn)的話題,所以我們不會(huì)詳細(xì)討論。我們將涵蓋足夠的基礎(chǔ)知識(shí)。
每個(gè)通用參數(shù)可以選擇性地用方差指示器分別標(biāo)記:
如果沒有指示方差,參數(shù)是不變的。
如果Foo<int>是一個(gè)子類型Foo<num>,那么Foo是協(xié)變的T?!癱o”是指“與”; 并且泛型類型的子類型關(guān)系與參數(shù)的子類型關(guān)系一起變?yōu)閰f(xié)變類型參數(shù)。
這是一個(gè)協(xié)變的例子:
<?hh
namespace Hack\UserDocumentation\Generics\Variance\Examples\Covariance;
// This class is readonly. Had we put in a setter for $this->t, we could not
// use covariance. e.g., if we had function setMe(T $x), you would get this
// cov.php:9:25,25: Illegal usage of a covariant type parameter (Typing[4120])
// cov.php:7:10,10: This is where the parameter was declared as covariant (+)
// cov.php:9:25,25: Function parameters are contravariant
class C<+T> {
public function __construct(private T $t) {}
}
class Animal {}
class Cat extends Animal {}
function f(C<Animal> $p1): void { var_dump($p1); }
function g(array<Animal> $p1): void { var_dump($p1); }
function run(): void {
f(new C(new Animal()));
f(new C(new Cat())); // accepted
g(array(new Animal(), new Animal()));
g(array(new Cat(), new Cat(), new Animal())); // arrays are covariant
}
run();
Output
object(Hack\UserDocumentation\Generics\Variance\Examples\Covariance\C)#1 (1) {
["t":"Hack\UserDocumentation\Generics\Variance\Examples\Covariance\C":private]=>
object(Hack\UserDocumentation\Generics\Variance\Examples\Covariance\Animal)#2 (0) {
}
}
object(Hack\UserDocumentation\Generics\Variance\Examples\Covariance\C)#1 (1) {
["t":"Hack\UserDocumentation\Generics\Variance\Examples\Covariance\C":private]=>
object(Hack\UserDocumentation\Generics\Variance\Examples\Covariance\Cat)#2 (0) {
}
}
array(2) {
[0]=>
object(Hack\UserDocumentation\Generics\Variance\Examples\Covariance\Animal)#1 (0) {
}
[1]=>
object(Hack\UserDocumentation\Generics\Variance\Examples\Covariance\Animal)#2 (0) {
}
}
array(3) {
[0]=>
object(Hack\UserDocumentation\Generics\Variance\Examples\Covariance\Cat)#2 (0) {
}
[1]=>
object(Hack\UserDocumentation\Generics\Variance\Examples\Covariance\Cat)#3 (0) {
}
[2]=>
object(Hack\UserDocumentation\Generics\Variance\Examples\Covariance\Animal)#4 (0) {
}
}
協(xié)變類型參數(shù)用于只讀類型。因此,如果可以以某種方式設(shè)置類型,則不能使用協(xié)方差。
協(xié)方差不能用作任何方法的參數(shù)類型,或者作為該類中任何可變屬性的類型。
如果Foo<num>是一個(gè)亞型的話Foo<int>,那Foo就是逆轉(zhuǎn)了T?!癱ontra”意思是“反對(duì)”; 泛型類型的子類型關(guān)系違背了參數(shù)的子類型關(guān)系到逆變類型參數(shù)。
這是一個(gè)反例的例子:
<?hh
namespace Hack\UserDocumentation\Generics\Variance\Examples\Contravariance;
// This class is write only. Had we put in a getter for $this->t, we could not
// use contravariance. e.g., if we had function getMe(T $x): T, you would get
// con.php:10:28,28: Illegal usage of a contravariant type
// parameter (Typing[4121])
// con.php:5:10,10: This is where the parameter was declared as
// contravariant (-)
// con.php:10:28,28: Function return types are covariant
class C<-T> {
public function __construct(private T $t) {}
public function setMe(T $val): void {
$this->t = $val;
}
}
class Animal {}
class Cat extends Animal {}
function main(): void {
$animal = new Animal();
$cat = new Cat();
$c = new C($cat);
// calling setMe with Animal on an instance of C that was initialized with Cat
$c->setMe($animal);
var_dump($c);
}
main();
Output
object(Hack\UserDocumentation\Generics\Variance\Examples\Contravariance\C)#3 (1) {
["t":"Hack\UserDocumentation\Generics\Variance\Examples\Contravariance\C":private]=>
object(Hack\UserDocumentation\Generics\Variance\Examples\Contravariance\Animal)#1 (0) {
}
}
逆變類型參數(shù)用于只寫類型。因此,如果類型可以以某種方式讀取,則不能使用逆變。(例如,序列化函數(shù)是一個(gè)很好的用例)。
逆變類型參數(shù)不能用作該類中任何方法的返回類型。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: