W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
與亞型相關(guān)的一個(gè)看似與直覺相反的領(lǐng)域是泛型。
<?hh
namespace Hack\UserDocumentation\Generics\Subtypes\Examples\Intuitive;
function echo_add(num $x, num $y): void {
echo $x + $y;
}
function get_int(): int {
return rand();
}
function run(): void {
$num1 = get_int();
$num2 = get_int();
echo_add($num1, $num2); // int is a subtype of num
}
run();
Output
2229204202
由于int是一個(gè)子類型num,類型轉(zhuǎn)換器通過傳遞int一個(gè)函數(shù)是完全正確的num。如果你傳遞一個(gè)float函數(shù)就沒問題了。如果你傳遞一個(gè)int和一個(gè)float函數(shù),也沒關(guān)系。
但是,你認(rèn)為類型分析者應(yīng)該接受嗎?
<?hh
namespace Hack\UserDocumentation\Generics\Subtypes\Examples\CounterIntuitive;
class Box<T> {
private Vector $box;
public function __construct(int $firstItem) {
$this->box = Vector {$firstItem};
}
public function add(T $v) {
$this->box[] = $v;
}
}
function addRandomToBox(Box<num> $x): void {
$x->add(rand());
}
function createBox(): Box<int> {
return new Box(3);
}
function run(): void {
$box = createBox(); // we have a Box<int>
addRandomToBox($box); // typechecker cannot guarantee a Box<int> now.
var_dump($box); // HHVM doesn't care since we erase generics anyway.
}
run();
Output
object(Hack\UserDocumentation\Generics\Subtypes\Examples\CounterIntuitive\Box)#2 (1) {
["box":"Hack\UserDocumentation\Generics\Subtypes\Examples\CounterIntuitive\Box":private]=>
object(HH\Vector)#1 (2) {
[0]=>
int(3)
[1]=>
int(123434323)
}
}
這似乎是應(yīng)該是有效的傳遞Box<int>一個(gè)函數(shù)期望一個(gè)Box<num>自從int是一個(gè)子類型num。然而,在泛型的情況下,子類型關(guān)系與其原始類型的對(duì)應(yīng)關(guān)系并不一致。
原因是因?yàn)槟愕姆盒蛯?duì)象是通過引用傳遞的,所以類型檢查者沒有辦法安全地知道你是否正在修改Boxin addRandomToBox()以包含不是的東西num。雖然明顯地向我們說,我們正在添加int中addRandomToBox(),該typechecker實(shí)際上不考慮發(fā)生了什么。所以不確定的是,返回給我們的還是一個(gè)Box<int>。
HHVM運(yùn)行時(shí)并不在意,因?yàn)槲覀冊(cè)谶\(yùn)行時(shí)會(huì)刪除泛型。
由于不可變的集合不能被改變array(即拷貝而不是引用),泛型與上面討論的子類型關(guān)系實(shí)際上會(huì)通過類型檢查器。這是因?yàn)轭愋蜋z查器可以保證實(shí)體在返回給調(diào)用者時(shí)不會(huì)被改變。
<?hh
namespace Hack\UserDocumentation\Generics\Subtypes\Examples\Immutable;
function addRandomToArray(array<num> $x): void {
$x[] = 3.2; // this is a copy, not a reference
}
function createArray(): array<int> {
return array(3);
}
function run(): void {
$arr = createArray(); // we have a array<int>
// typechecker CAN guarantee array<int> now since what is received by
// addRandomToArray() is a copy (passed-by-value)
addRandomToArray($arr);
var_dump($arr); // Still only going to contain 3, not the 3.2.
}
run();
Output
array(1) {
[0]=>
int(3)
}
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)系方式:
更多建議: