hack集合:語義

2018-10-19 11:35 更新

一般來說,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ù)組轉(zhuǎn)換為集合

使用數(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)換arrayVector,你的代碼可以打破由上面的例子所示。

幫助解決這個問題的一種方法是使用ImmVectorVector::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)
}

Equality on Collections ==

集合可以比較平等

$coll1 == $coll2;

這是規(guī)則:

  1. 兩個集合是否是相同類型的集合(忽略可變性)?如果沒有,那么平等就是false。
  2. 這兩個集合是否具有相同數(shù)量的值(或地圖的鍵)?如果沒有,那么平等就是false。
  3. 對于向量和對,每個索引的值是否等于==?如果沒有,那么平等false; 否則,平等就是true。
  4. 對于集合,一個中的每個值都包含在另一個中?如果沒有,那么平等false; 否則,平等就是true。
  5. 對于地圖,每個密鑰是否存在于另一個中===?如果沒有,那么平等就是false。如果是,相同的按鍵映射到每個集合中的相等值==?如果沒有,那么平等false; 否則平等是true。
<?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)

Identity on Collections ===

集合可以進(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()

您可以使用 list()和 VectorPair一樣可以使用數(shù)組。

雖然你可以使用list()與MapSet在運行時,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)

使用陣列內(nèi)置函數(shù)

Hack集合支持一些內(nèi)置的數(shù)組函數(shù)。

Sorting

方法有效集合
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是否定的。我們正在努力解決這個問題。

Querying

方法有效集合
array_keys()所有
array_key_exists()所有
array_values()所有
count()所有
idx()Vector, Map

idx()是一個函數(shù),如果沒有找到索引(null如果沒有指定索引)則返回一個collection,index和一個可選的默認(rèn)返回值。

Manipulation

方法有效集合
array_combine()所有
array_diff()所有
array_diff_key()所有
array_filter所有
array_intersect()所有
array_intersect_key()所有
array_map()所有
implode()所有
serialize()所有

Modification

方法有效集合
array_pop()所有
array_push()所有
array_shift()Vector, Set
array_unshiftVector, Set

Introspection

方法有效集合
var_dump()所有
print_r()所有
var_export()所有
debug_zval_dump所有

APC

方法有效集合
apc_store()所有

擴展

所有具體的收集類都是final(即它們不能被分類)。但是,您可以從集合基礎(chǔ)架構(gòu)提供的各種接口創(chuàng)建新的具體集合類。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號