类型检查
当我们开发一个新的 lint 或者改进现有的 lint 时,我们可能需要检索表达式 Expr
的类型 Ty
,这有很多原因。这可以通过利用 LateContext
来实现,LateContext
可用于 LateLintPass
。
LateContext
和 TypeckResults
lint 上下文 LateContext
和 TypeckResults
(由 LateContext::typeck_results
返回) 是 LateLintPass
中两个最有用的数据结构。它们允许我们跳转到类型定义和其他编译阶段,例如 HIR。
注意:
LateContext.typeck_results
的返回值是TypeckResults
,它是在类型检查步骤中创建的,它包含有用的信息,例如表达式的类型、解析方法的方式等等。
TypeckResults
包含有用的方法,例如 expr_ty
,它使我们可以访问给定表达式的底层结构 Ty
。
作为旁注,除了 expr_ty
之外,TypeckResults
还包含一个 pat_ty()
方法,该方法对于从模式中检索类型很有用。
Ty
Ty
结构体包含表达式的类型信息。让我们看看 rustc_middle
的 Ty
结构体来检查这个结构体
乍一看,这个结构体看起来相当深奥。但仔细一看,我们会发现这个结构体包含许多用于类型检查的有用方法。
例如,is_char
检查给定的 Ty
结构体是否对应于原始字符类型。
is_*
用法
在某些情况下,我们只需要检查表达式的 Ty
是否是特定类型,例如 char
类型,因此我们可以编写以下代码
此外,如果我们查看 is_char
的源代码,我们会发现一些非常有趣的东西
实际上,我们刚刚发现了 Ty
的 kind()
方法,它为我们提供了 Ty
的 TyKind
。
TyKind
TyKind
定义了 Rust 类型系统中类型的种类。查看 TyKind
文档,我们会看到它是一个包含超过 25 个变体的枚举,包括 Bool
、Int
、Ref
等项。
kind
用法
Ty
的 TyKind
可以通过调用 Ty.kind()
方法 返回。我们经常使用此方法在 Clippy 中执行模式匹配。
例如,如果我们想检查一个 struct
,我们可以检查 ty.kind
是否对应于 Adt
(代数数据类型),以及它的 AdtDef
是否是一个结构体
hir::Ty
和 ty::Ty
我们一直在谈论 ty::Ty
,但没有提及 hir::Ty
,但后者对于理解也很重要。
hir::Ty
表示用户所写的内容,而 ty::Ty
是编译器看待类型的方式,并且包含更多信息。例如
在这里,HIR 查看类型时没有“思考”它们,它知道函数接受 u32
并返回 u32
。就 hir::Ty
而言,这些可能是不同的类型。但在 ty::Ty
级别,编译器理解它们是相同的类型,深入的生命周期等等...
要从 hir::Ty
获取 ty::Ty
,您可以在函数体外部使用 lower_ty
函数,或者在函数体内部使用 TypeckResults::node_type()
方法。
警告:不要在函数体内部使用
lower_ty
,因为这可能会导致 ICE。
程序化地创建类型
程序化地创建类型的常见用例是当我们想要检查类型是否实现了 trait (参见 Trait 检查)。
这是一个如何为 u8
切片创建 Ty
的示例,即 [u8]
通常,我们依赖于 Ty::new_*
方法。这些方法定义了类型系统和 trait 系统用于定义和理解编写代码的基本构建块。
有用的链接
以下是一些有用的链接,可用于进一步探索本章涵盖的概念