指针

在Go语言中,指针是一种非常基本且重要的数据类型,它允许你直接访问和操作内存地址。指针的使用在C和C++等语言中非常普遍,但Go语言在提供指针功能的同时,也尽量简化了其复杂性,使得指针在Go中相对安全且易于使用。


1. 定义

指针是一个存储了内存地址的变量。在Go中,你可以通过 *Type 来声明一个指针,其中 Type 是指针指向的变量的类型。例如,*int 是一个指向 int 类型变量的指针。


var p *int

1

2. 初始化

你可以将变量的地址赋值给指针。使用 & 操作符来获取变量的内存地址。


var a int = 42

var p *int &a

1

2

3. 解引用指针

解引用(或称取消引用)指针意味着访问指针所指向的内存位置的值。在Go中,这是通过前置星号*完成的。


fmt.Println(*p) // 打印 p 指向的值,即 x 的值

*p = 21         // 修改 p 指向的值,即修改 x 的值

1

2

4. 指针的传递

在函数调用时,如果你希望函数能够修改调用者的变量,你可以将变量的指针传递给函数。


func modifyValue(p *int) {

*p = 100

}

1

2

3

测试方法


func Test_modifyValue(t *testing.T) {

num := 40


type args struct {

 p *int

}

tests := []struct {

 name string

 args args

}{

 {

  name: "init value = 1",

  args: args{&num},

 },

}

for _, tt := range tests {

 t.Run(tt.name, func(t *testing.T) {

  modifyValue(tt.args.p)

  fmt.Println("modify value = ", num)

 })

}

}


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

输出结果


=== RUN   Test_modifyValue

=== RUN   Test_modifyValue/init_value_=_1

modify value =  100

--- PASS: Test_modifyValue (0.00s)

   --- PASS: Test_modifyValue/init_value_=_1 (0.00s)

PASS

1

2

3

4

5

6

5. 指针的零值

未初始化的指针的默认值是 nil。尝试解引用一个 nil 指针会导致运行时错误(panic)。


var p *int

fmt.Println(*p)

// 这将导致运行时错误: invalid memory address or nil pointer dereference

1

2

3

6. 指针的比较

var a int = 42

var b int = 42

var p1 *int = &a

var p2 *int = &b

var p3 *int = &a


fmt.Println(p1 == p2) // 输出: false

fmt.Println(p1 == p3) // 输出: true

1

2

3

4

5

6

7

8

测试方法


func Test_comparePoint(t *testing.T) {

comparePoint()

}

1

2

3

输出结果


=== RUN   Test_comparePoint

false

true

--- PASS: Test_comparePoint (0.00s)

PASS

1

2

3

4

5

7. 其他(可选)

指针在数组、切面和结构体中会有重要作用。


// 指针数组

var ptrArray []*int

ptrArray = append(ptrArray, &a, &b)

fmt.Println(*ptrArray[0], *ptrArray[1]) // 输出: 42 42(假设a和b的初始值都是42)


// 指针切片

var ptrSlice []*int

ptrSlice = make([]*int, 2)

ptrSlice[0] = &a

ptrSlice[1] = &b

fmt.Println(*ptrSlice[0], *ptrSlice[1]) // 输出: 42 42(假设a和b的初始值都是42)


type Rectangle struct {

   Width, Height int

}


func (r *Rectangle) Area() int {

   return r.Width * r.Height

}


func (r *Rectangle) SetWidth(width int) {

   r.Width = width

}


func main() {

   rect := Rectangle{Width: 10, Height: 5}

   fmt.Println(rect.Area()) // 输出: 50

   rect.SetWidth(20)

   fmt.Println(rect.Area()) // 输出: 100

}


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

源码

// point_demo.go 文件

package point_demo


import "fmt"


func modifyValue(p *int) {

*p = 100

}


func comparePoint() {

var a int = 42

var b int = 42

var p1 *int = &a

var p2 *int = &b

var p3 *int = &a


fmt.Println(p1 == p2) // 输出: false

fmt.Println(p1 == p3) // 输出: true

}


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

// point_demo_test.go 文件

package point_demo


import (

"fmt"

"testing"

)


func Test_modifyValue(t *testing.T) {

num := 40


type args struct {

 p *int

}

tests := []struct {

 name string

 args args

}{

 {

  name: "init value = 1",

  args: args{&num},

 },

}

for _, tt := range tests {

 t.Run(tt.name, func(t *testing.T) {

  modifyValue(tt.args.p)

  fmt.Println("modify value = ", num)

 })

}

}


func Test_comparePoint(t *testing.T) {

comparePoint()

}