《Hack与HHVM权威指南》——2.2 其他泛型实体

简介:

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

2.2 其他泛型实体

类并不是唯一可以被泛型化的实体。

2.2.1 函数和方法

泛型函数在它的名字和参数列表的在圆括号之间有类型形参的列表。并且它可以像往常一样被调用,请看下面的例子:

function wrap<T>(T $value): Wrapper<T> {
  return new Wrapper($value);
}
function main(): void {
  $w = wrap(20);
}

就像这个例子所示 ,泛型函数的类型形参能够在函数的形参类型和返回类型这两个地方使用。
方法也可以是泛型的。如果一个方法存在于一个泛型类或者trait中,它能够使用其闭合类的类型形参,如下所示:

class Logger {
  public function logWrapped<Tval>(Wrapper<Tval> $value): void {
    // ...
  }
}
class Processor<Tconfig> {
  public function checkValue<Tval>(Tconfig $config, Tval $value): bool {
    // ...
  }
}

2.2.2 trait和接口

trait和接口两者都可以是泛型的。语法和泛型类的语法非常相似,都是在名称后面放置类型形参的列表:

trait DebugLogging<Tval> {
  public static function debugLog(Tval $value): void {
    // ...
  }
}
interface WorkItem<Tresult> {
  public function performWork(): Tresult;
}
任何使用一个泛型trait或者实现一个泛型接口的代码,都必须特别指明相关的类型实参:
class StringProducingWorkItem implements WorkItem<string> {
  use DebugLogging<string>;
  // ...
}

泛型类可以传递它的类型形参到它所实现的接口类型或使用的trait中。

class ConcreteWorkItem<Tresult> implements WorkItem<Tresult> {
  use DebugLogging<Tresult>;
  // ...
}

2.2.3 类型别名

关于类型别名的详细内容请参见3.2节的内容。它们能够通过立即添加类型形参列表到它们别名后而完成泛型化。
type matrix<T> = array<array<T>>;
这里有一个关于类型别名的非常有意思的泛型程序,在这个程序中,你将不会在右边的位置上使用类型形参。最好的示例就是序列化:

newtype serialized<T> = string;
function typed_serialize<T>(T $value): serialized<T> {
  return serialize($value);
}
function typed_unserialize<T>(serialized<T> $value): T {
  return unserialize($value);
}

鉴于普通的没有类型声明的serialize() API会丢失有关序列化值类型的相关信息,这个别名使类型检查器在大量类型的序列化版本中可以进行分辨。这在类型检查器中并不会引发错误,这是因为本质上来说,类型检查器并没有对它进行检查:unserialize()函数没有返回类型标注,所以类型检查器只是简单地相信它所做的事情,并且相关返回值也是正确的(请参见1.4.2节)。
在这里,类型检查器知道$unserialized变量是字符串类型。

$serialized_str = typed_serialize("hi");
$unserialized = typed_unserialize($serialized_str);

你还可以对每个序列化的值类型进行检查,以保证相关的变量类型。

function process_names(serialized<array<string>> $arr): void {
  foreach (typed_unserialize($arr) as $name) {
// 这里的$name已被确认为字符串
相关文章
|
Java 关系型数据库 数据库连接
【SpringBoot】入门到精通 这一篇就够了
【SpringBoot】入门到精通 这一篇就够了
413 1
|
存储 算法 编译器
【霍洛维兹数据结构】栈和队列 | 动态循环队列 | 迷宫问题 | 表达式 | 多重栈&多重队列
【霍洛维兹数据结构】栈和队列 | 动态循环队列 | 迷宫问题 | 表达式 | 多重栈&多重队列
232 0
|
开发工具 开发者 Windows
Windows10 IIS Web服务器安装配置
Windows10 IIS Web服务器安装配置
355 2
|
Shell 开发工具 git
git怎么处理文件夹名称大小写重命名问题
git怎么处理文件夹名称大小写重命名问题
494 0
|
Prometheus 监控 Cloud Native
微服务框架(二十二)Prometheus + Grafana 可视化监控
此系列文章将会描述Java框架Spring Boot、服务治理框架Dubbo、应用容器引擎Docker,及使用Spring Boot集成Dubbo、Mybatis等开源框架,其中穿插着Spring Boot中日志切面等技术的实现,然后通过gitlab-CI以持续集成为Docker镜像。 本文为Prometheus + Grafana 可视化监控的介绍,下篇为Prometheus + Grafana...
|
消息中间件 传感器 存储
MQTT介绍-发布/订阅模式
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议。
6805 0
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的周边美食推荐系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的周边美食推荐系统附带文章源码部署视频讲解等
125 1
|
存储 人工智能 安全
C语言假期作业 DAY 15
C语言假期作业 DAY 15
C语言假期作业 DAY 15
【JavaSE专栏83】线程插队,一个线程在另一个线程执行特定任务之前先执行
【JavaSE专栏83】线程插队,一个线程在另一个线程执行特定任务之前先执行
212 0
|
机器学习/深度学习 Linux
linux目录——文件管理
本文章介绍了目录和文件管理还有压缩方式
127 0
linux目录——文件管理