指针

Go语言中的指针

任何程序数据载入内内存后,在内存都有他们的地址。而为了保存一个数据在内存中的地址,我么就需要用到指针变量。

再Go语言中的指针不能进行偏移和运算,只需记住两个符号&(取地址),*(根据地质取值)。

指针地址和指针类型

每个变量在运行时都有一个地址,这个地址代表变量再内存中的位置,Go语言使用&字符放在变量前面进行”取地址“操作。Go语言值类型(int, float, bool, string, array, struct)都有其对应的指针类型,如*int, *int64,*string等。

1
ptr := &v //v的类型为T
1
2
3
4
5
//取地址
a := 16
b := &a
fmt.Println(a, &a) // a:10 ptr:0xc00001a078
fmt.Printf("%p %T %d", b, b, &b) // b:0xc00001a078 type:*int :0xc00001a078

指针取值

对普通变量使用&操作符可以获得这个变量的指针,对指针使用*操作可以获得该地址上存储的值。

1
2
3
4
5
c := "你好"
d := &c
fmt.Printf("%T %p\n", d, d) //*string //0xc00000a0b8
e := *d
fmt.Printf("%T %s\n", e, e) //string 你好

总结:

1
2
3
4
取地址操作符`&`和取值操作符`*`是一对互补操作符。&取出地址,*根据地址取出地址指向的值。
* 对变量进行取地址'&'操作时可以获得这个变量的指针变量。
* 指针变量的值是指针地址。
* 对指针变量进行取值'*'操作,可以获得指针变量指向的原始变量的值。

使用指针进行值传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func main(){
f := 30
aa(f)
fmt.Println(f)
bb(&f)
fmt.Println(f)
}

func aa(x int){
//修改形参的值
x =100
}

func bb(y *int){
//修改指向该指针地址的值
*y = 100
}

new()

new()是一个内置函数,他的函数签名如下:

1
func new(Type) *Type //出入一个指定的Type类型,返回的是Type类型的一个指针

new()函数不太常用,使用new()函数可以得到一个类型的指针,并且该指针对应的值为零值。

1
2
3
4
5
//通过new()获得某一类型的指针
g := new(int)
fmt.Printf("%T %d\n", g, *g) // *int 0
h := new(bool)
fmt.Printf("%T %v\n", h, *h) // *bool false

注意:声明指针类型的变量时,必须进行初始化才会拥有内存空间,才能对其进行赋值。

1
2
3
4
var i *int
i = new(int)
*i = 100
fmt.Println(*i)

make()

make函数也适用于分配内存的,区别于new(),它只适用于slice, map, channel的内存创建,而且它的返回值类型就是这三个类型本身,而不是指针类型,因为这三种类型就是引用类型,就没有必要返回他们的指针。

make()的函数签名:

1
func make(t Type, size ...IntegerType) Type

make()函数是无可替代的,我们在使用slice, map, channel时,都需要使用make()进行初始化,才可以对他们进行操作。

1
2
3
4
5
var k map[string]int //只是声明一个map,此时还没有分配内存,不可以使用
k = make(map[string]int)// 给声明的k变量分配内存空间,此时才可以使用k
k["a"] = 100
k["b"] = 10
fmt.Printf("%T len:%d value:%v", k, len(k), k) //map[string]int len:2 value:map[a:100 b:10]