hack泛型:Erasure
通过泛型参数化类型的能力为开发人员和代码用户提供了强大的可读性优势。它还提供了typechecker必要的信息,以确保您是代码的方式。例如,将Box<int>函数作为参数类型清楚地显示了Box应包含的类型,类型检查器也可以使用这些信息。
但是,除了异步函数的返回类型(Awaitable),对泛型的支持只能通过类型注释在类型分类器上进行 ; 它们在运行时不存在。泛型类型参数和参数,并在执行之前剥离(即擦除)。使用我们Box上面的例子,这意味着Box<int>真正Box在运行时,HHVM将允许你传递非int Box函数。
<?hh
namespace Hack\UserDocumentation\Generics\Erasure\Examples\TypeErasure;
class Box<T> {
private T $x;
public function __construct(T $x) {
$this->x = $x;
}
public function get(): T {
return $this->x;
}
}
function foo(Box<int> $b): void {
var_dump($b);
}
function run(): void {
$b = new Box(4);
$c = new Box("hi");
foo($b);
foo($c);
}
run();
/*****
* Typechecker error:
*
* File "type-erasure.php", line 23, characters 7-8:
* Invalid argument (Typing[4110])
* File "type-erasure.php", line 15, characters 18-20:
* This is an int
* File "type-erasure.php", line 21, characters 16-19:
* It is incompatible with a string
* File "type-erasure.php", line 15, characters 18-20:
* Considering that this type argument is invariant with respect to Hack\UserDocumentation\Generics\Erasure\Examples\TypeErasure\Box
****/
Output
object(Hack\UserDocumentation\Generics\Erasure\Examples\TypeErasure\Box)#1 (1) {
["x":"Hack\UserDocumentation\Generics\Erasure\Examples\TypeErasure\Box":private]=>
int(4)
}
object(Hack\UserDocumentation\Generics\Erasure\Examples\TypeErasure\Box)#2 (1) {
["x":"Hack\UserDocumentation\Generics\Erasure\Examples\TypeErasure\Box":private]=>
string(2) "hi"
}
虽然通用参数化确实是一个很大的好处,但是由于运行时的类型擦除,您需要注意一些限制。类型参数T不能在以下情况下使用:
- 使用new(例如new T())创建实例。
- Casting(例如(T) $value)。
- 在一个类的范围内,例如T::aStaticMethod()。
- 作为instanceof核查的正面。
- 作为静态属性的类型。
- 作为catch块中的异常的类型(例如,catch (T $exception))。
对于实例化,类范围和instanceof用法的可能替代,Hack提供了一个叫做Classname<T>扩展PHP表示的构造Foo::class。