codecamp

hack泛型:子类型

与亚型相关的一个看似与直觉相反的领域是泛型。

<?hh

namespace Hack\UserDocumentation\Generics\Subtypes\Examples\Intuitive;

function echo_add(num $x, num $y): void {
  echo $x + $y;
}

function get_int(): int {
  return rand();
}

function run(): void {
  $num1 = get_int();
  $num2 = get_int();
  echo_add($num1, $num2); // int is a subtype of num
}

run();

Output

2229204202

由于int是一个子类型num,类型转换器通过传递int一个函数是完全正确的num。如果你传递一个float函数就没问题了。如果你传递一个int和一个float函数,也没关系。

但是,你认为类型分析者应该接受吗?

<?hh

namespace Hack\UserDocumentation\Generics\Subtypes\Examples\CounterIntuitive;

class Box<T> {
  private Vector $box;
  public function __construct(int $firstItem) {
    $this->box = Vector {$firstItem};
  }
  public function add(T $v) {
    $this->box[] = $v;
  }
}

function addRandomToBox(Box<num> $x): void {
  $x->add(rand());
}

function createBox(): Box<int> {
  return new Box(3);
}

function run(): void {
  $box = createBox(); // we have a Box<int>
  addRandomToBox($box); // typechecker cannot guarantee a Box<int> now.
  var_dump($box); // HHVM doesn't care since we erase generics anyway.
}

run();

Output

object(Hack\UserDocumentation\Generics\Subtypes\Examples\CounterIntuitive\Box)#2 (1) {
  ["box":"Hack\UserDocumentation\Generics\Subtypes\Examples\CounterIntuitive\Box":private]=>
  object(HH\Vector)#1 (2) {
    [0]=>
    int(3)
    [1]=>
    int(123434323)
  }
}

这似乎是应该是有效的传递Box<int>一个函数期望一个Box<num>自从int是一个子类型num。然而,在泛型的情况下,子类型关系与其原始类型的对应关系并不一致。

原因是因为你的泛型对象是通过引用传递的,所以类型检查者没有办法安全地知道你是否正在修改Boxin addRandomToBox()以包含不是的东西num。虽然明显地向我们说,我们正在添加int中addRandomToBox(),该typechecker实际上不考虑发生了什么。所以不确定的是,返回给我们的还是一个Box<int>。

HHVM运行时并不在意,因为我们在运行时会删除泛型。

不变的集合和数组

由于不可变的集合不能被改变array(即拷贝而不是引用),泛型与上面讨论的子类型关系实际上会通过类型检查器。这是因为类型检查器可以保证实体在返回给调用者时不会被改变。

<?hh

namespace Hack\UserDocumentation\Generics\Subtypes\Examples\Immutable;

function addRandomToArray(array<num> $x): void {
  $x[] = 3.2; // this is a copy, not a reference
}

function createArray(): array<int> {
  return array(3);
}

function run(): void {
  $arr = createArray(); // we have a array<int>
  // typechecker CAN guarantee array<int> now since what is received by
  // addRandomToArray() is a copy (passed-by-value)
  addRandomToArray($arr);
  var_dump($arr); // Still only going to contain 3, not the 3.2.
}

run();

Output

array(1) {
  [0]=>
  int(3)
}
hack泛型:字符实体
hack泛型:约束条件
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }