hack集合:介紹

2018-10-20 11:19 更新

除了完全支持一刀切的PHP array 容器類型,Hack允許將額外的打字放置在數(shù)組上,并提供了一些實(shí)現(xiàn)更專門的集合模式的類。

Array Typing

在Hack中的數(shù)組行為類似于Generics可以提供關(guān)于它們?nèi)绾螌iT的附加類型信息。例如,一個(gè)無索引的字符串?dāng)?shù)組采用形式array<string>。類似地,對(duì)于索引數(shù)組,可以首先指定鍵類型(int或string),后跟值類型。因此,帶有字符串鍵和浮點(diǎn)值的字典可能看起來像array<string, float>。

由于數(shù)組的值側(cè)本身可能是一個(gè)數(shù)組(或一個(gè)Generic類),因此類型專門化可以嵌套,array<int, array<string, string>>其中包含數(shù)字索引的數(shù)組包含字符串字典。

<?hh

namespace Hack\UserDocumentation\Collections\Intro\Examples\Arr;

// array<string, string> is an array map with string keys and string values
function array_as_map(array<string, string> $arr): string {
  $r = substr(str_shuffle('ABCDEF'), 0, 1); // random letter
  return array_key_exists($r, $arr) ? $arr[$r] : 'Z';
}

// array<int> is an array vector with integer keys and integer values
function array_as_vector(array<int> $arr): int {
  $r = rand(0, 10);
  return array_key_exists($r, $arr) ? $arr[$r] : PHP_INT_MAX;
}

function run(): void {
  $v = array(100, 200, 300, 400);
  $v[] = 500; // element 5, value 500
  var_dump($v);
  var_dump(array_as_vector($v));

  $m = array('A' => 'California', 'B' => 'Oregon', 'C' => 'North Carolina');
  $m['D'] = 'Florida';
  var_dump($m);
  var_dump(array_as_map($m));
}

run();

Output

array(5) {
  [0]=>
  int(100)
  [1]=>
  int(200)
  [2]=>
  int(300)
  [3]=>
  int(400)
  [4]=>
  int(500)
}
int(9223372036854775807)
array(4) {
  ["A"]=>
  string(10) "California"
  ["B"]=>
  string(6) "Oregon"
  ["C"]=>
  string(14) "North Carolina"
  ["D"]=>
  string(7) "Florida"
}
string(7) "Florida"

Hack集合

雖然PHP數(shù)組是非常通用的,但靈活性偶爾會(huì)在性能,正確性或可讀性方面付出代價(jià)。Hack Collection類旨在通過以普通容器模式的形式提供深度專門的數(shù)組對(duì)象版本來解決這些問題:Vector, Map,和 Set。

集合類型

hack有七個(gè)集合:

類型描述
Vector可變的,int被索引的,有序的值序列。值可以是任何類型。所述indicies在開始0和結(jié)束處n-1,在那里n是元件的數(shù)量。
ImmVector一個(gè)不變的版本Vector。一旦ImmVector被創(chuàng)建,元件不能改變,刪除或添加。
Map可變的string或者int索引的索引序列的值序列。值可以是任何類型。訂單被記住。這與array使用中最相似
ImmMap一個(gè)不變的版本Map。一旦ImmMap被創(chuàng)建,元件不能改變,刪除或添加。
Set可變的,有序的唯一值集。值只能是intstring。有在無鑰匙Set
ImmSet一個(gè)不變的版本Set。一旦ImmSet被創(chuàng)建,元件不能改變,刪除或添加。
Pair完全兩個(gè)值的不可變序列。鑰匙是01。它們與元組類似,但靈活性較差。

可讀性

想象一下第三方功能聲明如下:

function foo(array<int, string> $arr): void {}

這是array一個(gè)帶有順序整數(shù)鍵的向量風(fēng)格數(shù)組嗎?或者可能是map具有潛在非順序整數(shù)鍵的風(fēng)格數(shù)組?這個(gè)數(shù)組中的值是否唯一?

現(xiàn)在想象這個(gè)函數(shù)聲明:

function bar(Vector<string> $vec): void {}

通過查看函數(shù)簽名,我們知道這些整數(shù)鍵是有序的和順序的。實(shí)際的關(guān)鍵數(shù)字可能與其持有的東西相關(guān)程度不大。

類似地,如果函數(shù)聲明是:

function bar(Set<string> $set): void {}

然后我們意識(shí)到這些整數(shù)鍵是不相關(guān)的,并且包含在該參數(shù)中的字符串都將具有唯一的值。

性能

在明顯的好處Vectors,并Sets有該按鍵可以由運(yùn)行時(shí)被忽略。對(duì)于Vectors,這意味著連續(xù)排列值并基于索引進(jìn)行快速查找和迭代。在Sets 的情況下,它實(shí)際上意味著(作為實(shí)現(xiàn)細(xì)節(jié))將內(nèi)部結(jié)構(gòu)轉(zhuǎn)換為內(nèi)部,使用值作為鍵(必須是唯一的),并忽略陣列對(duì)的另一半。這是PHP代碼中已經(jīng)提供的一種模式,但它消除了必須記住陣列內(nèi)部的認(rèn)知開銷,并且以比腳本代碼能夠更有效的方式進(jìn)行操作。

以下是密鑰收集類的操作的典型的攤銷時(shí)間復(fù)雜度array

CLASSACCESSITERATIONINSERTREMOVAL
VectorO(1)O(n)O(n)O(n)
MapO(1)O(n)O(1)O(1)
SetO(1)O(n)O(1)O(1)
PairO(1)O(1)N/AN/A
arrayO(1)O(n)O(1)O(1)

類型檢查

與可讀性有關(guān),Hack類型檢查器不能指出,例如,您的代碼的上下文是否將array使用的向量傳遞給array使用類似地圖的參數(shù)的函數(shù)。例如,以下代碼通過類型檢查器。

<?hh

namespace Hack\UserDocumentation\Collections\Intro\Examples\ArrTypeCheck;

// This is a array used like a map, but it can be passed an array used like
// a vector.
function array_as_map(array<int, int> $arr): int {
  $r = rand(0, 10); // random letter
  return array_key_exists($r, $arr) ? $arr[$r] : PHP_INT_MAX;
}

function run(): void {
  $v = array(100, 200, 300, 400);
  $v[] = 500; // element 5, value 500
  var_dump($v);
  var_dump(array_as_map($v));
}

run();

Output

array(5) {
  [0]=>
  int(100)
  [1]=>
  int(200)
  [2]=>
  int(300)
  [3]=>
  int(400)
  [4]=>
  int(500)
}
int(9223372036854775807)

但是,如果你把代碼相似的風(fēng)格,而是使用VectorMap,則typechecker很容易分辨的意圖。

<?hh

namespace Hack\UserDocumentation\Collections\Intro\Examples\MapTypeCheck;

// array<string, string> is an array map with string keys and string values
function array_as_map(Map<int, int> $arr): int {
  $r = rand(0, 10); // random letter
  return array_key_exists($r, $arr) ? $arr[$r] : -1;
}

function run(): void {
  $v = Vector { 100, 200, 300, 400 };
  $v[] = 500; // element 5, value 500
  var_dump($v);
  // The call to array_as_map will not typecheck because you are trying to pass
  // a Vector into a function expecting a Map. You will also get a runtime
  // error as well trying to do this.
  var_dump(array_as_map($v));
}

run();

Output

object(HH\Vector)#1 (5) {
  [0]=>
  int(100)
  [1]=>
  int(200)
  [2]=>
  int(300)
  [3]=>
  int(400)
  [4]=>
  int(500)
}
Catchable fatal error: Argument 1 passed to Hack\UserDocumentation\Collections\Intro\Examples\MapTypeCheck\array_as_map() must be an instance of HH\Map, HH\Vector given in /data/users/joelm/user-documentation/guides/hack/23-collections/01-introduction-examples/map-typecheck.php.type-errors on line 9

使用Hack集合可以讓類型檢查器使用更多的數(shù)據(jù)來嘗試確定你的代碼中是否有打字問題。

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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)