W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
一個不透明類型別名使用創(chuàng)建的newtype。與透明類型別名不同,小心組織源代碼,編譯器可以確保通用代碼不能直接訪問不透明別名的基礎(chǔ)類型。
每個不透明的別名類型都不同于其基礎(chǔ)類型,也不同于其他任何類型的別名。只有包含opaque類型別名定義的文件中的源代碼被允許訪問底層的實現(xiàn)。
考慮一個文件,point.inc.php它包含一個2D點類型和一些函數(shù)原語的不透明的別名定義:
<?hh
namespace Hack\UserDocumentation\TypeAliases\Opaque\Examples\AliasNoConstraint;
// point.php - Point implementation file
newtype Point = (int, int);
function createPoint(int $x, int $y): Point {
return tuple($x, $y);
}
function setX(Point $p, int $x): Point {
$p[0] = $x;
return $p;
}
function setY(Point $p, int $y): Point {
$p[1] = $y;
return $p;
}
function getX(Point $p): int {
return $p[0];
}
function getY(Point $p): int {
return $p[1];
}
只有那些需要知道Point
底層結(jié)構(gòu)的函數(shù)應(yīng)該在上面的Point
實現(xiàn)文件中定義。所有支持該Point
類型的通用函數(shù)都可以駐留在PointFunctions.php中,如下所示:
<?hh
namespace Hack\UserDocumentation\TypeAliases\Opaque\Examples\AliasNoConstraint;
// point-functions.php - Point's supporting functions
function distance_between_2_Points(Point $p1, Point $p2): float {
$dx = getX($p1) - getX($p2);
$dy = getY($p1) - getY($p2);
return sqrt($dx*$dx + $dy*$dy);
}
這里是一些創(chuàng)建和使用點的代碼:
<?hh
namespace Hack\UserDocumentation\TypeAliases\Opaque\Examples\AliasNoConstraint;
// test-point.php - User code that tests type Point
function run(): void {
$p1 = createPoint(5, 3);
var_dump($p1);
$p2 = createPoint(9, -5);
var_dump($p2);
$dist = distance_between_2_Points($p1, $p2);
echo "distance between points is " . $dist ."\n";
// But we cannot pass a tuple of two ints since they are not a Point
// This will give a Hack typechecker error
$will_not_type_check = distance_between_2_Points(tuple(2, 3), tuple(3, 4));
// However, the code will still run in HHVM
echo "distance between points is " . $will_not_type_check ."\n";
}
run();
/*
Here is the type error for $will_not_type_check
test-point.php:18:52,62: Invalid argument (Typing[4110])
point-functions.inc.php:9:36,40:
This is an object of type
Hack\UserDocumentation\TypeAliases\Opaque\Examples\AliasNoConstraint\Point
test-point.php:18:52,62: It is incompatible with a tuple
test-point.php:18:65,75: Invalid argument (Typing[4110])
point-functions.inc.php:9:47,51:
This is an object of type
Hack\UserDocumentation\TypeAliases\Opaque\Examples\AliasNoConstraint\Point
test-point.php:18:65,75: It is incompatible with a tuple
*/
Output
array(2) {
[0]=>
int(5)
[1]=>
int(3)
}
array(2) {
[0]=>
int(9)
[1]=>
int(-5)
}
distance between points is 8.9442719099992
distance between points is 1.4142135623731
與別名定義相同的文件,功能createPoint和朋友有---和需要---直接訪問任何點的元組中的整數(shù)字段。但是,任何其他文件不。
考慮一個包含以下不透明類型定義的文件:
<?hh
newtype Counter = int ;
任何包含這個文件的文件都不知道a Counter
是一個整數(shù),所以包含文件不能在該類型上執(zhí)行任何類似整數(shù)的操作。這是一個主要的限制,因為抽象類型的所謂的精心選擇的名稱Counter
,表明其價值可能增加和/或減少。我們可以通過向別名的定義添加一個類型約束來“解決”這個問題,如下所示:
<?hh
newtype Counter as int = int;
類型約束的存在允許將不透明類型視為具有由類型約束指定的類型,這將刪除一些別名的不透明。盡管約束的存在允許將別名類型隱式轉(zhuǎn)換為約束類型,但是沒有相反的方向定義轉(zhuǎn)換。在這個例子中,這意味著a Counter
可以被隱式地轉(zhuǎn)換成一個int
,而不是相反的。下面的例子會因為這個原因而無法檢查:
<?hh
// Assume this code is in a different file than where the Counter type is
// defined.
class A {
public Counter $c;
public function __construct() {
// This is prohibited, as there is no implicit conversion from int
// (the type of 0) to Counter
$this->c = 0;
}
}
類型約束必須是被別名的類型的子類型。
在下面的例子中,Point有一個約束(int, int); 因此我們可以通過Point任何方法期待(int, int)...但反之亦然!
<?hh
namespace Hack\UserDocumentation\TypeAliases\Opaque\Examples\AliasConstraint;
// point-constraint.inc.php - Point implementation file
newtype Point as (int, int) = (int, int);
function createPoint(int $x, int $y): Point {
return tuple($x, $y);
}
function setX(Point $p, int $x): Point {
$p[0] = $x;
return $p;
}
function setY(Point $p, int $y): Point {
$p[1] = $y;
return $p;
}
function getX(Point $p): int {
return $p[0];
}
function getY(Point $p): int {
return $p[1];
}
上面的兩個例子激發(fā)了幾個用例,在這樣的不透明類型別名中戳洞。
在這個Counter例子中,我們可能對a的值Counter以及它的維護方式有額外的限制,因此需要不透明度來確保合適的不變量得到尊重。這意味著我們不能讓任何人int成為一個Counter。但是換個方式就好了; 做一個Counter有道理的數(shù)學(xué)。
對于Point例如,它可能看起來像我們在很大程度上打破了抽象Point,而事實上我們。你可能不想編寫看起來像這樣的新代碼。但是,在轉(zhuǎn)換現(xiàn)有的非類型代碼時,它可能非常有用。我們可以引入一個新的Point不透明別名,但是有一個類型限制,用于向后兼容。任何新的代碼都會使用這個Point類型,從而受到Point抽象及其不變性的影響。(int, int)如果需要,現(xiàn)有的代碼可以繼續(xù)直接在元組上工作。但是,如果不Point經(jīng)過抽象,代碼就不能轉(zhuǎn)換回來,所以抽象不能被破壞。一旦所有的代碼都被轉(zhuǎn)換,別名上的約束可以被刪除,并且可以是完全不透明的。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: