1. Go语言中的指针不能进行偏移和运算,是安全指针
  2. 指针地址指针类型指针取值
  3. Go语言中的函数传参都是值拷贝,当我们想要修改某个变量的时候,我们可以创建一个指向该变量地址的指针变量。
  4. 传递数据使用指针,而无须拷贝数据。
  5. 类型指针不能进行偏移和运算。
  6. Go语言中的指针操作非常简单,只需要记住两个符号:
    • &(取地址)、*(根据地址取值)。

指针地址与指针类型

  1. 每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置,Go语言中使用&字符放在变量前面对变量进行**“取地址”**操作。
  2. Go语言中的值类型(intfloatboolstringarraystruct),对应的指针 *int*int64*string等。
1
2
3
4
5
6
// 取变量指针地址语法
ptr := &v // v的类型为T

// v: 代表被取地址的变量,类型为T
// ptr:用于接收地址的变量,ptr的类型就为*T,称做T的指针类型
// * 代表指针
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package main

import "fmt"

func main() {
    a := 10	// int类型
    b := &a	// *int类型

    // a:10 ptr:0xc00001a078 type:int
    fmt.Printf("a:%d ptr:%p type:%T\n", a, &a, a)

    // b:0xc00001a078 type:*int
    fmt.Printf("b:%p type:%T\n", b, b)

    // 0xc00000e018
    fmt.Println(&b)
}

指针取值

  1. 在对普通变量使用&操作符取地址后会获得这个变量的指针,然后可以对指针使用*操作,也就是指针取值。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package main

import "fmt"

func main() {
    a := 10 // int类型
    // 取变量a的地址,将指针保存到b中
    b := &a // *int类型

    fmt.Printf("type of b:%T\n", b) // type of b:*int

    // 指针取值(根据指针去内存取值)
    c := *b

    fmt.Printf("type of c:%T\n", c) // type of c:int
    fmt.Printf("value of c:%v\n", c)// value of c:10

    *b = 11
    fmt.Println(a, *b, c)   // 11 11 10
}

空指针

  1. 当一个指针被定义后没有分配到任何变量时,它的值为 nil
  2. 空指针的判断。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package main

import "fmt"

func main() {
    var p *string

    fmt.Println(p)  // <nil>
    fmt.Printf("p的值是%v\n", p) // p的值是<nil>

    if p != nil {
        fmt.Println("非空")
    } else {
        fmt.Println("空值") // 空值
    }
}

类型转换

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
    var ff float64 = 12.23

    ii := *(*uint64)(unsafe.Pointer(&ff)) // uint64 类型

    fmt.Printf("%064b \n", ii)

    ff1 := *(*float64)(unsafe.Pointer(&ii))

    fmt.Println(ff1)
    
    // Output:
    // 0100000000101000011101011100001010001111010111000010100011110110
    // 12.23
}

指针练习

  1. 程序定义一个int变量num的地址并打印。
  2. num的地址赋给指针ptr,并通过ptr去修改num的值。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
package main

import "fmt"

func main() {
    var a int
    fmt.Println(&a)
    var p *int
    p = &a
    *p = 20
    fmt.Println(a)
}

使用注意

  1. 常量】不能使用&取地址,常量是只读类型因此取地址没啥意义。
  2. 字符串元素】,比如&string[0]不能取地址,字符串也是只读类型对字符串中的符号取地址意义也不大。
  3. 字典元素】,比如&map[‘key’]不能取地址,字典的存储位置是经常变化的,因此对字典中元素取地址意义不大。

总结

  1. 取地址操作符&和取值操作符*是一对互补操作符。
    • &:取出地址;*:根据地址取出地址指向的值。
  2. 变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:
    • 对变量进行取地址(&)操作,可以获得这个变量的存储地址。
    • 指针变量的值是指针地址。
    • 对指针变量进行取值(*)操作,可以获得指针变量指向的原变量的值。
  3. 指针传值例子。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import "fmt"

func main() {
    a := 10

    modify1(a)

    fmt.Println(a)  // 10

    modify2(&a)

    fmt.Println(a)  // 100
}

func modify1(x int) {
    x = 100
}

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