hack集合:Examples

2018-10-26 11:13 更新

以下是有關(guān)如何使用Hack集合的各種示例。

簡單的矢量使用

這個(gè)簡單的例子顯示了如何創(chuàng)建,查詢,添加項(xiàng)目和從中刪除項(xiàng)目Vector。

<?hh

namespace Hack\UserDocumentation\Collections\Examples\Examples\Vec;

function use_vector(): void {
  $fruit_basket = Vector {'Banana', 'Apple'}; // initialize
  $fruit_basket[] = 'Orange'; // Add to the next available index, which is 2
  $fruit_basket[] = 'Banana'; // You can have duplicates
  var_dump($fruit_basket);
  try {
    // Can't use an explicit index that doesn't exist, even if it would be the
    // next available index.
    $fruit_basket[4] = 'Plum';
  } catch (\OutOfBoundsException $ex) {
    var_dump($ex->getMessage());
  }
  // Query the fruit at index 1
  var_dump($fruit_basket[1]);
  // Iterate over the entire fruit basket using foreach
  foreach ($fruit_basket as $fruit) {
    // This should only be a query. Do not add or remove from a Vector while
    // in a foreach
    var_dump($fruit);
  }
  // Iterate over some of the fruit basket using for and ints
  for ($i = 0; $i < $fruit_basket->count() - 2; $i++) {
    if ($i % 2 === 0) {
      // We can change the vector in a for loop by index
      $fruit_basket[$i] = 'Grape';
    }
  }
  var_dump($fruit_basket);
  // Remove an item
  $fruit_basket->removeKey(0);
  var_dump($fruit_basket);
}

use_vector();

Output

object(HH\Vector)#1 (4) {
  [0]=>
  string(6) "Banana"
  [1]=>
  string(5) "Apple"
  [2]=>
  string(6) "Orange"
  [3]=>
  string(6) "Banana"
}
string(30) "Integer key 4 is out of bounds"
string(5) "Apple"
string(6) "Banana"
string(5) "Apple"
string(6) "Orange"
string(6) "Banana"
object(HH\Vector)#1 (4) {
  [0]=>
  string(5) "Grape"
  [1]=>
  string(5) "Apple"
  [2]=>
  string(6) "Orange"
  [3]=>
  string(6) "Banana"
}
object(HH\Vector)#1 (3) {
  [0]=>
  string(5) "Apple"
  [1]=>
  string(6) "Orange"
  [2]=>
  string(6) "Banana"
}

簡單的地圖使用

這個(gè)簡單的例子顯示了如何創(chuàng)建,查詢,添加項(xiàng)目和從中刪除項(xiàng)目Map。

<?hh

namespace Hack\UserDocumentation\Collections\Examples\Examples\UsingMap;

function use_map(): void {
  $users = Map {1 => 'Joel', 2 => 'Fred'}; // initialize using keys and values
  try {
    // You must specify an explicit key when adding an item to a map
    // You will also get an Invalid Assignment type error when doing the below
    $users[] = 'Matthew'; // Add to the next available index, which is 2
  } catch (\InvalidArgumentException $ex) {
    var_dump($ex->getMessage());
  }
  // Instead add to a map this way
  $users[3] = 'Matthew';
  // Or this way
  $users[] = Pair {4, 'Rex'};
  var_dump($users);
  // Query the user at id 1
  var_dump($users[1]);
  // Iterate over the entire fruit basket using foreach
  foreach ($users as $id=>$name) {
    // This should only be a query. Do not add or remove from a Vector while
    // in a foreach
    echo 'The user name at id: ' . strval($id) . ' is ' . $name . PHP_EOL;
  }
  // Remove an item
  $users->removeKey(2);
  var_dump($users);
}

use_map();

Output

string(37) "Parameter must be an instance of Pair"
object(HH\Map)#1 (4) {
  [1]=>
  string(4) "Joel"
  [2]=>
  string(4) "Fred"
  [3]=>
  string(7) "Matthew"
  [4]=>
  string(3) "Rex"
}
string(4) "Joel"
The user name at id: 1 is Joel
The user name at id: 2 is Fred
The user name at id: 3 is Matthew
The user name at id: 4 is Rex
object(HH\Map)#1 (3) {
  [1]=>
  string(4) "Joel"
  [3]=>
  string(7) "Matthew"
  [4]=>
  string(3) "Rex"
}

運(yùn)用 filter()

filter() 允許您通過在集合的每個(gè)項(xiàng)目上應(yīng)用條件來創(chuàng)建當(dāng)前集合的子集(包括為空)的集合,如果該元素的條件為真,則它將成為新集合的一部分。

<?hh

namespace Hack\UserDocumentation\Collections\Examples\Examples\FilterM;

function filter_evens(Set<int> $numbers): Set<int> {
  return $numbers->filter($x ==> $x % 2 === 0);
  // We used a lambda above. This could have also been written as:
  //return $numbers->filter(function (int $x): bool {return $x % 2 === 0;});
}

function run(): void {
  $numbers = Set {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  var_dump(filter_evens($numbers));
}

run();

Output

object(HH\Set)#3 (6) {
  int(0)
  int(2)
  int(4)
  int(6)
  int(8)
  int(10)
}

請(qǐng)注意,我們使用lambda來創(chuàng)建過濾操作。我們也可以使用正常的關(guān)閉。

運(yùn)用 map()

map()允許您創(chuàng)建一個(gè)與map()調(diào)用的集合具有相同元素的集合,但是對(duì)每個(gè)元素應(yīng)用了一些操作。

<?hh

namespace Hack\UserDocumentation\Collections\Examples\Examples\MapM;

function apply_prefix(Vector<string> $phrases): Vector<string> {
  return $phrases->map($x ==> 'Hello ' . $x);
  // We used a lambda above. This could have also been written as:
  //return $phrases->map(function (string $x): string {return 'Hello' . $x;});
}

function run(): void {
  $phrases = Vector {'Joel', 'Rex', 'Fred', 'Matthew', 'Tim', 'Jez'};
  var_dump(apply_prefix($phrases));
}

run();

Output

object(HH\Vector)#3 (6) {
  [0]=>
  string(10) "Hello Joel"
  [1]=>
  string(9) "Hello Rex"
  [2]=>
  string(10) "Hello Fred"
  [3]=>
  string(13) "Hello Matthew"
  [4]=>
  string(9) "Hello Tim"
  [5]=>
  string(9) "Hello Jez"
}

請(qǐng)注意,我們正在使用lambda來創(chuàng)建映射操作。我們也可以使用正常的關(guān)閉。

參考語義

Hack集合具有引用語義,而數(shù)組具有值語義。

<?hh

namespace Hack\UserDocumentation\Collections\Examples\Examples\Reference;

function vec_ref(Vector<int> $vec): Vector<int> {
  for ($i = 0; $i < $vec->count(); $i++) {
    // Changing the vector here actually changes the vector from the calling
    // site
    $vec[$i] += 2;
  }
  return $vec;
}

function arr_value(array<int> $arr): array<int> {
  for ($i = 0; $i < count($arr); $i++) {
    // Changing the array does not change the array at the calling site
    $arr[$i] += 2;
  }
  return $arr;
}

function run(): void {
  echo "-- VECTOR HAS REFERENCE SEMANTICS --\n\n";
  $vec = Vector {0, 1, 2, 3, 4};
  var_dump($vec);
  vec_ref($vec);
  var_dump($vec);
  echo "\n\n-- ARRAY HAS VALUE SEMANTICS --\n\n";
  $arr = array(0, 1, 2, 3, 4);
  var_dump($arr);
  arr_value($arr);
  var_dump($arr);
}

run();

Output

-- VECTOR HAS REFERENCE SEMANTICS --

object(HH\Vector)#1 (5) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(2)
  [3]=>
  int(3)
  [4]=>
  int(4)
}
object(HH\Vector)#1 (5) {
  [0]=>
  int(2)
  [1]=>
  int(3)
  [2]=>
  int(4)
  [3]=>
  int(5)
  [4]=>
  int(6)
}


-- ARRAY HAS VALUE SEMANTICS --

array(5) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(2)
  [3]=>
  int(3)
  [4]=>
  int(4)
}
array(5) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(2)
  [3]=>
  int(3)
  [4]=>
  int(4)
}

Lazy

Hack集合使用該方法提供了Scala類視圖lazy()。通常,當(dāng)您創(chuàng)建集合的實(shí)例時(shí),您將創(chuàng)建一個(gè)嚴(yán)格版本的集合。因此,當(dāng)您創(chuàng)建一個(gè)包含一百萬個(gè)元素的集合時(shí),會(huì)立即為所有這些元素分配內(nèi)存。然而,在一個(gè)視圖通過lazy(),則可以創(chuàng)建一個(gè)非嚴(yán)格集合,使得當(dāng)您使用的方法類似map()或filter()在收集(即,變壓器方法),所述元件僅被訪問時(shí)進(jìn)行計(jì)算。

此示例顯示了如何lazy()在一個(gè)相當(dāng)大的集合上使用,以及對(duì)集合的嚴(yán)格和非嚴(yán)格版本的時(shí)間。由于我們最終只需要5個(gè)元素,所以懶惰的視圖實(shí)際上允許我們?cè)跐M足我們所需的5之后停止,而無需實(shí)際分配所有1000000個(gè)元素。

<?hh

namespace Hack\UserDocumentation\Collections\Examples\Examples\LazyM;

$vector = new Vector(range(0, 1000000));

$s = microtime(true);
$non_lazy = $vector->filter($x ==> $x % 2 === 0)->take(5);
$e = microtime(true);

var_dump($non_lazy);
echo "Time non-lazy: " . strval($e - $s) . PHP_EOL;

// Using a lazy view of the vector can save us a bunch of time, possibly even
// cutting this call time by 90%.
$s = microtime(true);
$lazy = $vector->lazy()->filter($x ==> $x % 2 === 0)->take(5);
$e = microtime(true);

var_dump($lazy->toVector());
echo "Time lazy: " . strval($e - $s) . PHP_EOL;

Output

object(HH\Vector)#4 (5) {
  [0]=>
  int(0)
  [1]=>
  int(2)
  [2]=>
  int(4)
  [3]=>
  int(6)
  [4]=>
  int(8)
}
Time non-lazy: 0.27819204330444
object(HH\Vector)#9 (5) {
  [0]=>
  int(0)
  [1]=>
  int(2)
  [2]=>
  int(4)
  [3]=>
  int(6)
  [4]=>
  int(8)
}
Time lazy: 0.015102863311768

Indexish

Indexish是一個(gè)表示可以由密鑰建立索引的集合的接口。集合中的鍵可以是string或int。因此,您可以用于Indexish表示具有這兩種關(guān)鍵類型之一的Hack集合。

<?hh

namespace Hack\UserDocumentation\Collections\Examples\Examples\IndexishIface;

// Since this returns Indexish, we can return both a Vector and Map from this
// function. Could also return a Pair too (not a Set since you don't access a
// Set by key).
function return_indexish(bool $which): \Indexish<int, mixed> {
  return $which ? Vector {100, 200, 300} : Map {0 => 'A', 1 => 'B', 2 => 'C'};
}

function run(): void {
  var_dump(return_indexish(true));
  var_dump(return_indexish(false));
}

run();

Output

object(HH\Vector)#1 (3) {
  [0]=>
  int(100)
  [1]=>
  int(200)
  [2]=>
  int(300)
}
object(HH\Map)#1 (3) {
  [0]=>
  string(1) "A"
  [1]=>
  string(1) "B"
  [2]=>
  string(1) "C"
}

創(chuàng)建新集合

當(dāng)前的具體收集類被標(biāo)記為final。也就是說,它們不能被直接擴(kuò)展和分類。但是,您可以使用提供的接口創(chuàng)建新的集合類。這個(gè)例子將不會(huì)創(chuàng)建一個(gè)完整的新集合,因?yàn)檫@樣很多的方法必須被實(shí)現(xiàn)Iterable<T> 比這里介紹的更多的審查和細(xì)節(jié)。

但是,這個(gè)例子確實(shí)顯示了如果你想創(chuàng)建一個(gè)新的集合集必須實(shí)現(xiàn)的所有方法。

<?hh

namespace Hack\UserDocumentation\Collections\Examples\Examples\SimpleColl;

final class AbsurdSet<Tv> implements \MutableSet<Tv> {
  private \Set $cs;

  public function __construct(?Traversable<Tv> $values) {
    if (!$values) {
      $this->cs = Set {0};
    } else {
      invariant($values !== null, "won't happen");
      $this->cs = new Set($values);
      foreach ($values as $value) {
        // Yes, this is ridiculous
        if (is_int($value)) {
          $this->cs[] = $value + 2;
        }
      }
    }
  }

  public function values(): \Vector<Tv> {
    return $this->cs->values();
  }
  public function keys(): \Vector<mixed> {
    return $this->cs->keys();
  }
  public function map<Tu>((function(Tv): Tu) $fn): \Set<Tu> {
    return $this->cs->map($fn);
  }
  public function mapWithKey<Tu>(
    (function(mixed, Tv): Tu) $fn): \Set<Tu> {
    return $this->cs->mapWithKey($fn);
  }
  public function filter((function(Tv): bool) $fn): \Set<Tv> {
    return $this->cs->filter($fn);
  }
  public function filterWithKey(
    (function(mixed, Tv): bool) $fn): \Set<Tv> {
    return $this->cs->filterWithKey($fn);
  }
  public function zip<Tu>(
    Traversable<Tu> $traversable): \Set<Pair<Tv, Tu>> {
    return $this->cs->zip($traversable);
  }
  public function take(int $n): \Set<Tv> {
    return $this->cs->take($n);
  }
  public function takeWhile((function(Tv): bool) $fn): \Set<Tv> {
    return $this->cs->takeWhile($fn);
  }
  public function skip(int $n): \Set<Tv> {
    return $this->cs->skip($n);
  }
  public function skipWhile((function(Tv): bool) $fn): \Set<Tv> {
    return $this->cs->skipWhile($fn);
  }
  public function slice(int $start, int $len): \Set<Tv> {
    return $this->cs->slice($start, $len);
  }
  public function concat<Tu super Tv>(
    Traversable<Tu> $traversable): \Vector<Tu> {
    return $this->cs->concat($traversable);
  }
  public function firstValue(): ?Tv {
    return $this->cs->firstValue();
  }
  public function firstKey(): mixed {
     return $this->cs->firstKey();
  }
  public function lastValue(): ?Tv {
     return $this->cs->lastValue();
  }
  public function lastKey(): mixed {
     return $this->cs->lastKey();
  }
  public function isEmpty(): bool {
     return $this->cs->isEmpty();
  }
  public function count(): int {
     return $this->cs->count();
  }
  public function contains<Tu super Tv>(Tu $value): bool {
    return $this->cs->contains($value);
  }
  public function add(Tv $value): AbsurdSet<Tv> {
    return new AbsurdSet($this->cs->add($value));
  }
  public function addAll(?Traversable<Tv> $values): AbsurdSet<Tv> {
    return new AbsurdSet($this->cs->addAll($values));
  }
  public function clear(): \Set<Tv> {
    return $this->cs->clear();
  }
  public function getIterator(): \KeyedIterator<mixed, Tv> {
    return $this->cs->getIterator();
  }
  public function items(): \Iterable<Tv> {
    return $this->cs->items();
  }
  public function lazy(): \KeyedIterable<mixed, Tv> {
    return $this->cs->lazy();
  }
  public function remove(Tv $value): AbsurdSet<Tv> {
    return new AbsurdSet($this->cs->remove($value));
  }
  public function toArray(): array<Tv, Tv> {
    return $this->cs->toArray();
  }
  public function toImmMap(): \ImmMap<mixed, Tv> {
    return $this->cs->toImmMap();
  }
  public function toImmSet(): \ImmSet<Tv> {
    return $this->cs->toImmSet();
  }
  public function toImmVector(): \ImmVector<Tv> {
    return $this->cs->toImmVector();
  }
  public function toMap(): \Map<mixed, Tv> {
    return $this->cs->toMap();
  }
  public function toSet(): \Set<Tv> {
    return $this->cs->toSet();
  }
  public function toVector(): \Vector<Tv> {
    return $this->cs->toVector();
  }
  public function toKeysArray(): array<Tv> {
    return $this->cs->toKeysArray();
  }
  public function toValuesArray(): array<Tv> {
    return $this->cs->toValuesArray();
  }
}

$aset = new AbsurdSet(array(2, 3));
var_dump($aset);

Output

object(Hack\UserDocumentation\Collections\Examples\Examples\SimpleColl\AbsurdSet)#1 (1) {
  ["cs":"Hack\UserDocumentation\Collections\Examples\Examples\SimpleColl\AbsurdSet":private]=>
  object(HH\Set)#2 (4) {
    int(2)
    int(3)
    int(4)
    int(5)
  }
}
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

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

編程獅公眾號(hào)