Go语言基础之指针

1 指针

1.1 Go语言中指针介绍

指针是程序载入到内存中的所对应的地址,为了保存数据在内存中对应的地址,就有了指针变量。指针在内存中的示意图如下:

Go语言基础之指针

Go语言中的指针不能进行偏移和运算,是安全指针。在Golang中只有&(取址)和*(取值)两个操作。

1.2 指针和地址的区别

地址:是内存地址(用字节来描述的内存地址)

指针:指针存储执行类型数据在内存空间中对应的地址。比如说string类型的指针,其只能存储string变量类型的指针

1.3 指针和指针类型

如同上面所说,指针是地址,但是地址不是指针,因为指针有其对应的类型,如*intfloat64*string等。

取变量指针的语法如下:

ptr := &v   // v的类型为T
  • v:代表被取地址的变量,类型为T
  • ptr:用于接收地址的变量,ptr的类型就是*T,称其为T的指针类型

代码演示:

func main()  {
    var a int
    fmt.Println(a)      //0
    b := &a  // 取变量a的内存地址
    fmt.Printf("b=%v\n", b)         //b=0xc00000a0c0
    fmt.Printf("type b:%T\n", b)    //type b:*int

    c := "tom"
    // b = &c  //go语言是静态类型,变量只能存储一种类型的地址
    // golang中的地址只能读不能操作
    fmt.Printf("&c=%v\n", &c)   //&c=0xc0000321f0

    d := 100
    b = &d
    fmt.Println(b)      //0xc00000a0d8
    // *取地址对应的值
    fmt.Println(*b)     //100
    // 指针可以做逻辑判断
    fmt.Println(b == &d)    //true
}

对于上述代码的说明:

  • b := &a在内存中的示意图:

Go语言基础之指针

  • 语法糖:因为go语言中的指针不支持地址的修改,所以编译器会默认修改指针对应的值。也就是说,如果有一个指针类型的变量ptr,对其进行一些运算(加法运算),在使用的过程中*ptr + 2等价于ptr + 2

1.4 指针的使用场景

指针通常会在函数之间的传参时使用。函数在传参时是通过值传参的,比如参数是数组,在传参的过程中形参会对实参的值拷贝一份存储在形参变量中,如果这个数组很大时,那么这个过程就很浪费内存,这时就可以使用指针进行传参,不论数组有多大,传参过程中所耗费的内存空间都是固定的。

指针传值示例:

func modify1(x int) {
    x = 100
}

func modify2(x *int) {
    *x = 100
}

func main() {
    a := 10
    modify1(a)
    fmt.Println(a) // 10
    modify2(&a)
    fmt.Println(a) // 100
}

2 new和make

在Go语言中对于值类型的声明不需要分配内存空间,因为它们在声明的时候已经默认分配好了内存空间;而对于引用类型的以下变量,不仅要声明它,还需对其进行内存空间的分配,比如:

var a *int的意思是a是一个int类型的指针,但是在内存中没有其存放的地方,应当声明其存放的地址,以及该地址对应的值(初始化)。

Golang中的newmake都是内建函数,主要用来分配内存。

2.1 new

new函数主要给一些值类型(int系列,数组)的指针分配内存空间,其函数签名如下:

func new(Type) *Type

其中,

  • Type表示类型,new函数只接受一个参数,这个参数是一个类型
  • *Type表示类型指针,new函数返回一个指向该类型内存地址的指针

new函数不太常用,使用new函数得到的是一个值类型的指针,并且该指针对应的值为该类型的零值。如下示例:

func main() {
    a := new(int)
    b := new(bool)
    fmt.Printf("%T\n", a) // *int
    fmt.Printf("%T\n", b) // *bool
    fmt.Println(*a)       // 0
    fmt.Println(*b)       // false
}

在声明了一个指针变量后,需要对其进行初始化。按照如下方式使用new函数对a进行初始化以及赋值操作:

func main() {
    var a *int
    a = new(int)
    *a = 10
    fmt.Println(*a)
}

2.2 make

make函数主要给一些引用类型(slice,map,channel)进行初始化,该函数返回的类型就是引用类型本身,而不是指针类型。因为其本身就是引用类型,所以就没有必要返回指针。

make的函数签名如下:

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

make函数使用示例:

func main() {
    var b map[string]int    //声明了一个map类型的变量b
    b = make(map[string]int, 10)    //开辟存储长度为10的map类型
    b["age"] = 20
    fmt.Println(b)
}

2.3 new和make的区别

  • 二者都是用来做内存的分配
  • make用于对引用类型的初始化,返回的是引用类型的本身
  • new用于值类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针

相关推荐