1、概念
空白标识符是由下划线 "_" 表示的特殊标识符,对于不被使用且存在的变量,可以使用空白标识符表示。空白标识符不占用内存、不保存值、不能读取,用来接收不需要的返回值,规避编译器 "变量声明未使用" 报错。
官方术语:空白标识符(blank identifier,`_`)。
"匿名变量" 是国内很多教程、书籍对 `_` 的俗称,不是 Go spec 里的官方名词。
很多中文资料直接把 `_` 叫做匿名变量;但是严格区分的话,Go 规范里还有另一类真正的匿名变量(`new(T)`、复合字面量,没有名字的内存实体),这个是最容易混淆的坑!
2、使用场景
空白标识符通常用于以下 4 种场景。
(1)函数有多个返回值,但只需要使用一个返回值,不使用的返回值使用空白标识符表示。
(2)导入某个包,不调用包的任何变量或函数,只执行包的初始化函数 init()。
(3)在使用 for - range 循环遍历切片、数组、映射或通道时,若不需要索引,可使用空白标识符忽略它。
(4)类型断言,判断某个类型是否实现接口,没有实现则报告编译错误。
2.1 函数有多个返回值,但只需要使用一个返回值
函数有多个返回值,但只需要使用一个返回值,不使用的返回值使用空白标识符表示。
Go
package main
import "fmt"
func myFunc() (string, string, int) { // 自定义函数,设置3个返回值
name := "张三"
sex := "男"
age := 20
return name, sex, age
}
func main() {
name, _, _ := myFunc() // 调用函数,只获取第一个返回值
fmt.Printf("姓名: %s", name)
}
2.2 导入某个包,只执行包的初始化函数
导入某个包,不调用包的任何变量或函数,只执行包的初始化函数 init()。
Go
package main
import (
"fmt"
_ "blank-demo/mypkg" // 空白标识符匿名导入,只会执行这个包的 init() 函数,main 代码里不会直接使用该包
)
func main() {
fmt.Println("main 函数执行了")
}
2.3 使用 for - range 循环时,忽略索引
在使用for - range循环遍历切片、数组、映射或通道时,若不需要索引,可使用空白标识符忽略它。
Go
package main
import "fmt"
func main() {
numbers := []int{1, 2, 3, 4, 5}
for _, num := range numbers { // 遍历 numbers 切片时,由于不需要索引,所以用空白标识符_忽略了索引
fmt.Println(num)
}
}
2.4 类型断言,判断某个类型是否实现接口
类型断言,判断某个类型是否实现接口,没有实现则报告编译错误。在 Go 语言中,接口实现是隐式的。可利用空白标识符来显式检查某个类型是否实现了特定接口。
Go
package main
import "fmt"
// 定义一个接口
type Speaker interface {
Say() string
}
// Dog 结构体
type Dog struct{}
func (d Dog) Say() string {
return "汪汪汪"
}
// Cat 结构体(故意不实现Say方法)
type Cat struct{}
// 空白标识符:编译校验 Dog 是否实现 Speaker
var _ Speaker = Dog{}
// 如果取消注释下面这一行,编译直接报错:Cat does not implement Speaker
// var _ Speaker = Cat{}
func main() {
var s Speaker = Dog{}
fmt.Println(s.Say())
}