hack泛型介绍

2018-11-09 15:25 更新

某些类型(类,接口和特性)及其方法可以参数化; 也就是说,它们的声明可以有一个或多个称为类型参数的占位符名称,当实例化一个类或调用方法时,它们通过类型参数与类型相关联。具有这种占位符名称的类型或方法分别称为泛型类型或泛型方法。顶层函数也可以参数化,从而产生泛型函数。

一个泛型类的例子是Vector<T>从Hack集合实现。T被称为一个类型参数,这是使通用的。它可以保存任何类型的值,从int到类的一个实例。然而,对于类的任何实例化来说,一旦一个类型已经被关联T,就不能改变为保持任何其他类型。

<?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是一个Vector<int>,$y而是一个Vector<string>。A Vector和 Vector不是相同的类型。

方法和功能也可以是通用的。一个用例是当他们需要操纵泛型类时:

<?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

上面的例子展示了一个swap<T>()在泛型Box<T>类上运行 的泛型函数。

泛型允许开发人员编写一个具有任何类型参数的类或方法,同时保持类型安全。没有泛型,完成一个类似的模型将需要创建BoxInt和BoxString类,并很快得到冗长。或者,我们可以把它$value当作一个mixed类型来进行instanceof()检查,这意味着将一个字符串插入到一个int框中不会引发类型检查错误,而只会在运行时发现。

元数

泛型类型或方法的arity是为该类型或方法声明的类型参数的数量。因此,类Vector有arity 1.哈克库通用容器类Map实现了一个有序的,字典样式的集合。这种类型有arity 2,并且使用了一个键类型和一个值类型,Map<int, Employee>例如,这个类型可以用来表示由一个整数员工编号索引的一组Employee对象。

在通用参数列表中,参数名称必须

  • 是不同的
  • 都以字母T开头
  • 与用于封闭类,接口或特征的泛型参数不同。

在以下情况下,类Vector有一个类型参数,Tv所以有arity 1.方法map也有一个类型参数Tu,所以有arity 1。

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

在以下的情况下,类Map有两个类型参数,Tk并且Tv,因此具有元数2.方法zip具有一个,Tu,所以有元数1。

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

在以下情况下,函数maxValue具有一个类型参数T,因此具有参数1。

function maxValue<T>(T $p1, T $p2): T { … }
以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号