Go语言值,指针,引用类型 - 立志做一个好的程序员 - 博客园
Go语言的指针与C或C++的指针类似,但是Go语言的指针不支持指针运算,这样就消除了在C或C++程序中一些潜在的问题。由于Go语言有自己的垃圾回收器,并且会自动管理内存,所以Go语言也不需要像C或C++一样使用free函数或者delete操作符。
Go语言的指针创建后可以像Java和Python中对象的引用一样使用。
在Go语言中,对于布尔变量或数值类型或字符串类型或数组都是按照值传递的:值在传递给函数或者方法时会被复制一份,然后方法或函数使用的是复制的这份值,也就不会对原值产生什么影响。一般情况下,对于布尔变量或数值类型或字符串类型的按值传递是非常廉价的,Go语言编译器会在传递过程中进行安全优化。
但是在Go语言中,字符串是不可变的,因此在进行修改字符串时(例如使用+=操作),Go语言必须创建一个新的字符串,然后复制原始的字符串并将其添加到新字符串之后,对于大字符串来说,操作的代价可能会比较大。
对于大字符串是这样,对于数组进行值传递也是如此。为了解决可能产生的巨大代价,Go语言使用数组切片来代替数组的使用。传递一个切片的代价跟传递字符串差不多,无论该切片的长度或容量是多大。对切片进行复制修改操作也不会像字符串那样需要创建新的切片,因为切片是可变的,属于引用类型。
Go语言中的引用类型有:映射(map),数组切片(slice),通道(channel),方法与函数。
由于Go语言存在垃圾回收器,因此在一个本地变量不再被使用时(不再被引用或者不在作用于范围)就会被垃圾回收器回收掉,这时本地变量的生命周期由它们的作用域决定。那如果我们想要管理本地变量的生命周期呢?这时就需要使用指针来管理本地变量,只要该变量至少存在一个指针,那么该变量的生命周期就可以独立于作用域。
使用指针能让我们控制变量的生命周期,不受作用域的影响,另外变量在传递过程中成本最小化,且可以轻易的修改变量的内容,而不是对复制的值进行操作。指针是一个变量,这个变量实际上是保存了另一个变量的内存地址,任何被指针保存了内存地址的变量都可以通过指针来修改内容。指针的传递非常廉价。
在使用指针前,我们需要明白两个操作符的含义
①操作符& : 当作二元操作符时,是按位与操作;当作一元操作符时,是返回该变量的内存地址。
②操作符* : 当作二元操作符时,是相乘的操作;当作一元操作符(解引用操作符)时,是返回该指针指向的变量的值,其实就是解除变量的指针引用,返回该变量的值。
指针的创建与使用,可以看下面的代码实例
func main() {
a := 3
p := &a //这里是获取变量a的内存地址,并将其赋值给变量p
fmt.Printf("a的值为 %v, a的指针是 %v ,p指向的变量的值为 %v\n",a,p,*p)
}
-----output-----
a的值为 3, a的指针是 0xc042060080 ,p指向的变量的值为 3
func fn() *int {
a := 10
return &a
}
type Config struct {
val int
str string
}
func fn2() *Config {
b := &Config{val: 5,
str: "ni"}
return b
}
func main() {
x2 := fn2()
x3 := fn2()
fmt.Println("x address:", x2)
fmt.Println("x=", *x2)
fmt.Println("x address:", x3)
fmt.Println("x=", *x3)
x := fn()
y := fn()
fmt.Println("x address:", x)
fmt.Println("x=", *x)
fmt.Println("y address:", y)
fmt.Println("y=", *y)
var virtualHosts []*envoy_config_route_v3.VirtualHost
vh := &envoy_config_route_v3.VirtualHost{
Name: name,
Domains: []string{domain},
}
virtualHosts = append(virtualHosts, vh)
}