这行代码:
var _ business.Handler = (*QueryList)(nil)
作用
与 var _ business.Handler = new(QueryList) 类似,它的主要作用是在编译时检查 *QueryList 类型是否实现了 business.Handler 接口。其具体作用是:
-
类型安全检查
如果*QueryList没有实现business.Handler中声明的所有方法,编译器会抛出错误。 -
声明用途
这是一个惯用法,表明QueryList或其指针类型 (*QueryList) 被设计为实现business.Handler接口。这是 Go 社区中常用的实践,尤其是在大型项目中,用于文档化和防止错误。
为什么使用 (*QueryList)(nil)
这里 (nil) 是一个零值指针,只是为了表示类型,而不是实际分配任何内存。
(*QueryList)(nil)是一个指向QueryList的空指针,它没有分配实际的QueryList实例。- 编译器会检查
*QueryList是否满足business.Handler接口的约束。
运行时和内存开销
这行代码不会对运行时或内存产生任何开销,原因如下:
-
编译时行为
Go 编译器在编译时完成类型检查,不会生成对应的运行时代码,也不会分配任何内存。 -
nil指针不会分配内存
(nil)表示空指针,既不初始化结构体,也不分配任何实际内存空间。
为什么更推荐 (*QueryList)(nil) 而不是 new(QueryList)
虽然两者都能实现编译时检查,但有一些细微区别:
| 方式 | 优点 |
|---|---|
var _ business.Handler = (*QueryList)(nil) | 语义明确,仅用于类型检查,不会分配实例,更简洁,惯用法。 |
var _ business.Handler = new(QueryList) | 编译时检查有效,但 new(QueryList) 明显看起来像是要实际创建一个实例(尽管它并未执行),容易引起误解。 |
因此,社区更倾向于使用 (*QueryList)(nil)。
总结
var _ business.Handler = (*QueryList)(nil)
- 作用:在编译时检查
*QueryList是否实现了business.Handler接口; - 开销:无运行时或内存开销;
- 惯例:推荐用
(*QueryList)(nil),因为它更明确表达了“仅进行类型检查”的意图。