hack泛型介紹

2018-11-09 15:25 更新

某些類型(類,接口和特性)及其方法可以參數(shù)化; 也就是說,它們的聲明可以有一個(gè)或多個(gè)稱為類型參數(shù)的占位符名稱,當(dāng)實(shí)例化一個(gè)類或調(diào)用方法時(shí),它們通過類型參數(shù)與類型相關(guān)聯(lián)。具有這種占位符名稱的類型或方法分別稱為泛型類型或泛型方法。頂層函數(shù)也可以參數(shù)化,從而產(chǎn)生泛型函數(shù)。

一個(gè)泛型類的例子是Vector<T>從Hack集合實(shí)現(xiàn)。T被稱為一個(gè)類型參數(shù),這是使通用的。它可以保存任何類型的值,從int到類的一個(gè)實(shí)例。然而,對于類的任何實(shí)例化來說,一旦一個(gè)類型已經(jīng)被關(guān)聯(lián)T,就不能改變?yōu)楸3秩魏纹渌愋汀?/p>

<?hh

namespace Hack\UserDocumentation\Generics\Intro\Examples\Vec;

/* Signature of Vector
*
* class Vector<Tv> implements MutableCollection<Tv> {
* :
* }
*
*/

function main_vec(): void {
  $x = Vector {1, 2, 3, 4}; // T is associated with int
  var_dump($x);
  $y = Vector {'a', 'b', 'c', 'd'}; // T is associated with string
  var_dump($y);
}

main_vec();

Output

object(HH\Vector)#1 (4) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
  [3]=>
  int(4)
}
object(HH\Vector)#2 (4) {
  [0]=>
  string(1) "a"
  [1]=>
  string(1) "b"
  [2]=>
  string(1) "c"
  [3]=>
  string(1) "d"
}

$x是一個(gè)Vector<int>,$y而是一個(gè)Vector<string>。A Vector和 Vector不是相同的類型。

方法和功能也可以是通用的。一個(gè)用例是當(dāng)他們需要操縱泛型類時(shí):

<?hh

namespace Hack\UserDocumentation\Generics\Intro\Examples\GenericMethods;

// Testing generic methods in a non-generic class.

class Box<T> {
  public T $value;
  public function __construct(T $v) {
    $this->value = $v;
  }
}

function swap<T>(Box<T> $a, Box<T> $b) : void {
  $temp = $a->value;
  $a->value = $b->value;
  $b->value = $temp;
}

function do_int_swap(): void {
  $y = new Box(3);
  $z = new Box(4);
  echo $y->value." ".$z->value;
  swap($y, $z);
  echo $y->value." ".$z->value;
}

function do_string_swap(): void {
  $y = new Box('a');
  $z = new Box('b');
  echo $y->value." ".$z->value;
  swap($y, $z);
  echo $y->value." ".$z->value;
}

function doAll(): void {
  do_int_swap();
  do_string_swap();
}

doAll();

Output

3 44 3a bb a

上面的例子展示了一個(gè)swap<T>()在泛型Box<T>類上運(yùn)行 的泛型函數(shù)。

泛型允許開發(fā)人員編寫一個(gè)具有任何類型參數(shù)的類或方法,同時(shí)保持類型安全。沒有泛型,完成一個(gè)類似的模型將需要?jiǎng)?chuàng)建BoxInt和BoxString類,并很快得到冗長?;蛘撸覀兛梢园阉?value當(dāng)作一個(gè)mixed類型來進(jìn)行instanceof()檢查,這意味著將一個(gè)字符串插入到一個(gè)int框中不會(huì)引發(fā)類型檢查錯(cuò)誤,而只會(huì)在運(yùn)行時(shí)發(fā)現(xiàn)。

元數(shù)

泛型類型或方法的arity是為該類型或方法聲明的類型參數(shù)的數(shù)量。因此,類Vector有arity 1.哈克庫通用容器類Map實(shí)現(xiàn)了一個(gè)有序的,字典樣式的集合。這種類型有arity 2,并且使用了一個(gè)鍵類型和一個(gè)值類型,Map<int, Employee>例如,這個(gè)類型可以用來表示由一個(gè)整數(shù)員工編號(hào)索引的一組Employee對象。

在通用參數(shù)列表中,參數(shù)名稱必須

  • 是不同的
  • 都以字母T開頭
  • 與用于封閉類,接口或特征的泛型參數(shù)不同。

在以下情況下,類Vector有一個(gè)類型參數(shù),Tv所以有arity 1.方法map也有一個(gè)類型參數(shù)Tu,所以有arity 1。

final class Vector<Tv> implements MutableVector<Tv> {
  …
  public function map<Tu>((function(Tv): Tu) $callback): Vector<Tu> { … }
}

在以下的情況下,類Map有兩個(gè)類型參數(shù),Tk并且Tv,因此具有元數(shù)2.方法zip具有一個(gè),Tu,所以有元數(shù)1。

final class Map<Tk, Tv> implements MutableMap<Tk, Tv> {
  …
  public function zip<Tu>(Traversable<Tu> $iter): Map<Tk, Pair<Tv, Tu>> { … }
}

在以下情況下,函數(shù)maxValue具有一個(gè)類型參數(shù)T,因此具有參數(shù)1。

function maxValue<T>(T $p1, T $p2): T { … }
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

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

編程獅公眾號(hào)