揭秘 Go 接口为何偏爱指针类型
2023-09-03 19:48:40
指针类型和值类型是 Go 中最基本的两种数据类型。值类型存储实际的值,而指针类型存储指向实际值的内存地址。当函数接收值类型时,它将创建该类型的副本,然后将副本传递给函数。这意味着函数只能对副本进行操作,而不能改变原始值。
当函数接收指针类型时,它将获得指向实际值的内存地址。这意味着函数可以直接访问和修改实际值。因此,指针类型常用于需要修改函数参数的情况。
接口是 Go 中的一种特殊类型,它允许不同类型的对象共享相同的行为。接口定义了一组方法,任何实现了这些方法的类型都可以实现该接口。当函数接收接口类型时,它并不关心具体实现该接口的类型是什么,它只关心该接口定义的方法。
但是,接口不能接收值类型,只能接收指针类型。这是因为值类型无法保证一定能够取得到地址。例如,如果一个值类型是匿名字段类型,那么它就没有地址。此外,如果一个值类型是逃逸的,那么它也有可能没有地址。
因此,为了保证接口能够接收所有实现了该接口的类型,接口只能接收指针类型。指针类型总是可以取到地址,因此接口可以放心接收指针类型。
在实际开发中,我们经常需要使用接口来定义函数的参数类型。例如,我们可以定义一个名为 Service
的接口,该接口定义了 Get()
和 Set()
两个方法。然后,我们可以实现该接口,并使用该接口来定义函数的参数类型。
type Service interface {
Get() string
Set(value string)
}
type ServiceImpl struct {
value string
}
func (s *ServiceImpl) Get() string {
return s.value
}
func (s *ServiceImpl) Set(value string) {
s.value = value
}
func main() {
var s Service = &ServiceImpl{}
s.Set("Hello, World!")
fmt.Println(s.Get()) // 输出: Hello, World!
}
在这个示例中,我们定义了 Service
接口和 ServiceImpl
类型。ServiceImpl
类型实现了 Service
接口,并且我们在 main()
函数中使用了 Service
接口来定义函数的参数类型。
在上面的示例中,我们使用了指针类型 *ServiceImpl
来实现 Service
接口。这是因为 Service
接口只能接收指针类型。如果我们使用值类型 ServiceImpl
来实现 Service
接口,那么编译器会报错。
这就是 Go 接口为何偏爱指针类型的原因。指针类型总是可以取到地址,因此接口可以放心接收指针类型。