一般來說,Hack系列應(yīng)該是您決定使用新代碼時的第一選擇。它們提供了所需的可讀性,性能和類型可檢測性,而不會在靈活性方面犧牲很多。
也就是說,有一個關(guān)鍵領(lǐng)域,你必須認(rèn)識到集合和數(shù)組之間的差異。
Hack集合有參考語義。這意味著集合被視為對象,對集合進(jìn)行的修改會影響已分配或以某種方式復(fù)制的集合。
數(shù)組有價值語義。因此,對數(shù)組的修改將不會對已分配或以某種方式復(fù)制到其中的數(shù)組造成影響。
<?hh
namespace Hack\UserDocumentation\Collections\Semantics\Examples\RefVal;
function foo(Vector<int> $vec): void {
$vec[1] = 500;
var_dump($vec);
}
function bar(array<int> $arr): void {
$arr[1] = 500;
var_dump($arr);
}
function reference_semantics(): void {
$vec = Vector {1, 2, 3};
var_dump($vec);
$cp_vec = $vec;
var_dump($cp_vec); // The two vectors are the same reference
$vec[0] = 100; // $cp_vec is also affected by the change. They are the same.
var_dump($vec);
var_dump($cp_vec);
foo($vec); // $vec will be affected by anything foo does to it.
var_dump($vec);
}
function value_semantics(): void {
$arr = array (1, 2, 3);
var_dump($arr);
$cp_arr = $arr;
var_dump($cp_arr); // The two arrays have the same values, but are copies.
$arr[0] = 100; // $cp_arr is not affected by this
var_dump($arr);
var_dump($cp_arr);
bar($arr); // $arr is not affected by anytnig bar does to it
var_dump($arr);
}
function run(): void {
echo "--- REFERENCE SEMANTICS ---\n\n";
reference_semantics();
echo "\n\n--- VALUE SEMANTICS ---\n\n";
value_semantics();
}
run();
Output
--- REFERENCE SEMANTICS ---
object(HH\Vector)#1 (3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
object(HH\Vector)#1 (3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
object(HH\Vector)#1 (3) {
[0]=>
int(100)
[1]=>
int(2)
[2]=>
int(3)
}
object(HH\Vector)#1 (3) {
[0]=>
int(100)
[1]=>
int(2)
[2]=>
int(3)
}
object(HH\Vector)#1 (3) {
[0]=>
int(100)
[1]=>
int(500)
[2]=>
int(3)
}
object(HH\Vector)#1 (3) {
[0]=>
int(100)
[1]=>
int(500)
[2]=>
int(3)
}
--- VALUE SEMANTICS ---
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
array(3) {
[0]=>
int(100)
[1]=>
int(2)
[2]=>
int(3)
}
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
array(3) {
[0]=>
int(100)
[1]=>
int(500)
[2]=>
int(3)
}
array(3) {
[0]=>
int(100)
[1]=>
int(2)
[2]=>
int(3)
}
上面的例子顯示了引用和值語義之間的區(qū)別。這在函數(shù)調(diào)用中也是如此。
使用數(shù)組將現(xiàn)有代碼轉(zhuǎn)換為集合時,數(shù)組具有值語義和集合的引用語義實際上非常重要。
<?hh
namespace Hack\UserDocumentation\Collections\Semantics\Examples\Converting;
function foo_with_vector(Vector<int> $vec): void {
$vec[] = 5;
}
function foo_with_array(array<int> $arr): void {
$arr[] = 5;
}
function run(): void {
$arr = array (1, 2, 3);
foo_with_array($arr);
$arr[] = 4; // The call to foo_with_array did not affect this $arr.
var_dump($arr);
// Many would expect the same sequence of code to work the same
$vec = Vector {1, 2, 3};
foo_with_vector($vec);
$vec[] = 4; // Uh oh, reference semantics at work. foo_with_vector affects us
var_dump($vec);
}
run();
Output
array(4) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
}
object(HH\Vector)#1 (5) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(5)
[4]=>
int(4)
}
所以,如果你有一些自動代碼修改轉(zhuǎn)換array到Vector,你的代碼可以打破由上面的例子所示。
幫助解決這個問題的一種方法是使用ImmVector并Vector::immutable()確保在將其傳遞給函數(shù)時不能修改集合。
<?hh
namespace Hack\UserDocumentation\Collections\Semantics\Examples\ConvertingImm;
function foo_with_vector(ImmVector<int> $vec): void {
try {
// The type checker actually won't allow this, but you can run this
// and catch the exception
$vec[] = 5;
} catch (\InvalidOperationException $ex) {
echo "Cannot modify immutable collection. Create copy first\n";
$cp_vec = new Vector($vec);
$cp_vec[] = 5;
var_dump($cp_vec);
}
}
function foo_with_array(array<int> $arr): void {
$arr[] = 5;
}
function run(): void {
$arr = array (1, 2, 3);
foo_with_array($arr);
$arr[] = 4; // The call to foo_with_array did not affect this $arr.
var_dump($arr);
$vec = Vector {1, 2, 3};
// Now any change in foo_with_vector won't affect this $vec
foo_with_vector($vec->immutable());
$vec[] = 4;
var_dump($vec);
}
run();
Output
array(4) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
}
Cannot modify immutable collection. Create copy first
object(HH\Vector)#4 (4) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(5)
}
object(HH\Vector)#1 (4) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
}
集合可以比較平等
$coll1 == $coll2;
這是規(guī)則:
<?hh
namespace Hack\UserDocumentation\Collections\Semantics\Examples\Equality;
function run(): void {
$vecA = Vector {1, 2, 3};
$vecB = Vector {1, 2, 3};
$vecC = Vector {4, 5, 6};
$vecD = Vector {2, 1, 3};
$setA = Set {1, 2, 3};
$setB = Set {3, 2, 1};
$mapA = Map {1 => 'A', 2 => 'B'};
$mapB = Map {2 => 'B', 1 => 'A'};
var_dump($vecA == $vecB); // true
var_dump($vecA == $vecC); // false, different values
var_dump($vecA == $vecD); // false, same values, but different order
var_dump($setA == $setB); // true, same values, order doesn't matter
var_dump($mapA == $mapB); // true, ordering of keys doesn't matter
}
run();
Output
bool(true)
bool(false)
bool(false)
bool(true)
bool(true)
集合可以進(jìn)行身份??比較。
$ coll1 === $ coll2;
只有身份才能評估true兩個集合是否是相同的對象。否則的話false。
<?hh
namespace Hack\UserDocumentation\Collections\Semantics\Examples\Identity;
function run(): void {
$vecA = Vector {1, 2, 3};
$vecB = Vector {1, 2, 3};
$vecC = $vecA;
$setA = Set {1, 2, 3};
$setB = Set {3, 2, 1};
$setC = $setB;
$mapA = Map {1 => 'A', 2 => 'B'};
$mapB = Map {2 => 'B', 1 => 'A'};
var_dump($vecA === $vecB); // false, not the same object
var_dump($vecA === $vecC); // true, the same object
var_dump($setA === $setB); // false, not the same object
var_dump($setA === $setC); // false, not the same object
var_dump($setB === $setC); // true, the same object
var_dump($mapA === $mapB); // false, not the same object
}
run();
Output
bool(false)
bool(true)
bool(false)
bool(false)
bool(true)
bool(false)
您可以使用 list()和 Vector和Pair一樣可以使用數(shù)組。
雖然你可以使用list()與Map和Set在運行時,hack typechecker將拋出一個錯誤。請注意,您必須有一個零整數(shù)鍵和隨后的有序鍵為Map和Set; 否則你會得到一個OutOfBoundsException。
<?hh
namespace Hack\UserDocumentation\Collections\Semantics\Examples\Liust;
function run(): void {
$vecA = Vector {1, 2, 3};
$setA = Set {0, 1, 2};
$mapA = Map {1 => 'A', 0 => 'B'};
$pairA = Pair {999, 9999};
$setB = Set {200, 300};
list($v1, $v2, $v3) = $vecA;
list($s1, $s2, $s3) = $setA;
list($m1, $m2) = $mapA;
list($p1, $p2) = $pairA;
try {
// Exception will be thrown since there is no 0 and 1 value in the Set
// to serve as a key-like value
list($x, $y) = $setB;
} catch (\OutOfBoundsException $ex) {
var_dump($ex->getMessage());
}
var_dump($v1);
var_dump($v2);
var_dump($v3);
var_dump($s1);
var_dump($s2);
var_dump($s3);
var_dump($m1);
var_dump($m2);
var_dump($p1);
var_dump($p2);
}
run();
Output
string(28) "Integer key 1 is not defined"
int(1)
int(2)
int(3)
int(0)
int(1)
int(2)
string(1) "B"
string(1) "A"
int(999)
int(9999)
Hack集合支持一些內(nèi)置的數(shù)組函數(shù)。
方法 | 有效集合 |
---|---|
sort() | Vector |
rsort() | Vector |
usort() | Vector |
asort() | Map |
arsort() | Map |
ksort() | Map |
krsort() | Map |
uasort() | Map |
uksort() | Map |
natsort() | Map |
natcasesort() | Map |
Pairs不支持排序,因為它們是不可變的。您可以將其轉(zhuǎn)換Pair為可變集合,然后進(jìn)行排序。
目前,與排序Sets的Hack類型檢查器和HHVM不同意的矛盾是矛盾的。例如,typechecker可以調(diào)用sort()一個Set,但HHVM不是; 和HHVM都確定了要在通話asort()上Set,但typechecker是否定的。我們正在努力解決這個問題。
方法 | 有效集合 |
---|---|
array_keys() | 所有 |
array_key_exists() | 所有 |
array_values() | 所有 |
count() | 所有 |
idx() | Vector , Map |
idx()
是一個函數(shù),如果沒有找到索引(null
如果沒有指定索引)則返回一個collection,index和一個可選的默認(rèn)返回值。
方法 | 有效集合 |
---|---|
array_combine() | 所有 |
array_diff() | 所有 |
array_diff_key() | 所有 |
array_filter | 所有 |
array_intersect() | 所有 |
array_intersect_key() | 所有 |
array_map() | 所有 |
implode() | 所有 |
serialize() | 所有 |
方法 | 有效集合 |
---|---|
array_pop() | 所有 |
array_push() | 所有 |
array_shift() | Vector , Set |
array_unshift | Vector , Set |
方法 | 有效集合 |
---|---|
var_dump() | 所有 |
print_r() | 所有 |
var_export() | 所有 |
debug_zval_dump | 所有 |
方法 | 有效集合 |
---|---|
apc_store() | 所有 |
所有具體的收集類都是final(即它們不能被分類)。但是,您可以從集合基礎(chǔ)架構(gòu)提供的各種接口創(chuàng)建新的具體集合類。
更多建議: