《Hack与HHVM权威指南》——2.4 约束

本节书摘来自华章出版社《Hack与HHVM权威指南》一书中的第2章,第2.4节,作者 Owen Yamauchi,更多章节内容可以访问云栖社区“华章计算机”公众号查看。

2.4 约束

在泛型实体的定义内,类型检查器对于类型形参一无所知,这是掌握泛型类型的要点所在。这就意味着,当一个值的类型是个类型形参时,你不能对它能做很多事情,你不能调用它,不能在它上调用方法或者访问属性,不能对它进行索引,不能在它上面做算术运算,或者其他诸如此类的事情。但一个重要的例外是相等和恒等比较(==,===,!=,!==)被允许。
当然,可以通过对类型形参添加一个约束而做出一些改变。这个约束将限制类型形参允许是什么值。语法就是添加一个关键词“as”以及一个类型标注在类型形参列表的识别符后面。让我们回到那个关于Wrapper类的引导示例上来,并且对它的类型形参添加一个约束:

class Wrapper<Tval as num> {
  private Tval $value;
  public function __construct(Tval $value) {
    $this->value = $value;
  }
  public function setValue(Tval $value): void {
    $this->value = $value;
  }
  public function getValue(): Tval {
    return $this->value;
  }
}

在这里,对于一个和num兼容的类型值,任何能够使用这个类的代码都能够这样做:

function f(int $int, float $float, num $num,
           int $nullint, string $string, mixed $mixed): void {
  $w = new Wrapper($int);    // OK
  $w = new Wrapper($float);    // OK
  $w = new Wrapper($num);    // OK
  $w = new Wrapper($nullint);     // 错误
  $w = new Wrapper($string);    // 错误
  $w = new Wrapper($mixed);    // 错误
}

这就意味着,在Wrapper定义内部,对于“类型为Tval的值可以进行的操作和对于类型为num的值可以进行的操作”是一样的。所以,我们可以添加这样一个方法:

class Wrapper<Tval as num> {
  private Tval $value;
  public function add(Tval $addend): void {
    // $this->value是个已知的num类型,所以可以在上面使用+=操作符   
    $this->value += $addend;
  }
  // ...
}

可以使用任何合法的类型标注作为约束。最常见的情况就是使用一个类或者接口的名字作为约束。这样做的话,你将可以调用在类或者接口中声明好的方法:

interface HasID {
  public function getID(): int;
}

function write_to_database<Tval as HasID>(Tval $value): void {
  $id = $value->getID();
  // ...
}

每个类型形参至多有一个约束。如果你希望限制一个类型形参为某个单独的类,而这个类又实现了多个特定的接口,你可以通过对它们进行扩展,创建一个合并所有上述接口的新接口,然后在约束中使用这个新的接口。

interface HasID {
  public function getID(): int;
}
interface HasHashCode {
  public function getHashCode(): string;
}
interface HasIDAndHashCode extends HasID, HasHashCode {
}
function write_to_cache<Tval as HasIDAndHashCode>(Tval $value): void {
  $id = $value->getID();
  $hash_code = $value->getHashCode();
  // ...
}

这里并没有办法表述像Tval那样必须实现这个接口或者那个接口的约束。
正如我们所看到的一样,约束的类型可以是任何合法的类型标注。这包括其他的类型形参,甚至在同一个形参列表中靠前的类型形参。例如,下面约束的使用方式是合法的:

class GenericClass<Tclass> {
  public function genericMethod<Tmethod as Tclass>(): Tmethod {
    // ...
  }
}

function lookup<Tvalue, Tdefault as Tvalue>(string $key,
                                            ?Tdefault $default = null): Tvalue {
  // ...
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值