codecamp

hack泛型:约束条件

hack泛型类型约束条件表示为了被接受为给定类型参数的类型参数,类型必须满足的要求。(例如,它可能必须是给定的类类型或该类类型的子类型,或者可能必须实现给定的接口。

hack泛型类型约束有两种,分别由关键字as和super关键字指定。每个都在下面讨论。

通过as指定约束

考虑下面的例子,其中类Complex有一个类型参数T,并且有一个约束num:

<?hh

namespace Hack\UserDocumentation\Generics\Constraints\Examples\Constraint;


class Complex<T as num> {
  private T $real;
  private T $imag;
  public function __construct(T $real, T $imag) {
    $this->real = $real;
    $this->imag = $imag;
  }
  public static function add(Complex<T> $z1, Complex<T> $z2): Complex<num> {
    return new Complex($z1->real + $z2->real, $z1->imag + $z2->imag);
  }

  public function __toString(): string {
    if ($this->imag === 0.0) {
      // Make sure to cast the floating-point numbers to a string.
      return (string) $this->real;
    } else if ($this->real === 0.0) {
      return (string) $this->imag . 'i';
    } else {
      return (string) $this->real . ' + ' . (string) $this->imag . 'i';
    }
  }
}

function run(): void {
  $c1 = new Complex(10.5, 5.67);
  $c2 = new Complex(4, 5);
  // You can add one complex that takes a float and one that takes an int.
  echo "\$c1 + \$c2 = " . Complex::add($c1, $c2) . "\n";
  $c3 = new Complex(5, 6);
  $c4 = new Complex(9, 11);
  echo "\$c3 + \$c4 = " . Complex::add($c3, $c4) . "\n";
}

run();

Output

$c1 + $c2 = 14.5 + 10.67i
$c3 + $c4 = 14 + 17i

没有这个as num约束,会报告一些错误,包括以下内容:

  • return方法中的语句add对未知类型的值执行算术运算T,但是对于所有可能的类型参数没有定义算术。
  • if方法中的语句__toString将未知类型的值T与a float进行比较,但是没有为所有可能的类型参数定义这样的比较。
  • return方法中的语句会__toString取消未知类型的值T,但是对于所有可能的类型参数都没有定义这样的操作。同样,一个未知类型的值T正在与一个字符串连接。

该run()代码创建float并int分别情况下,类的Complex。

总之,T as U断言T必须是一个子类型U。

通过。指定约束 super

与as类型约束不同,T super U断言T必须是超类型的U。

这种约束相当奇特,但解决了多种类型“碰撞”时遇到的一个有趣的问题。下面是一个如何concat在库接口类型中使用方法的例子ConstVector

interface ConstVector<+T> {
  public function concat<Tu super T>(ConstVector<Tu> $x): ConstVector<Tu>;
  // ...
}

考虑我们调用concatVector<float>和a 连接的情况Vector<int>。由于它们有一个共同的超类型,num所以这个super约束允许检查器确定这num是推断的类型Tu


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; }