Golang指针

golang中的指针与c语言指针略有不同。

1、基本类型的指针

1
2
var num int = 10
var p *int = &num // 指针的类型为所指向的变量的类型前加*

2、数组的指针与指针数组

数组的指针:

1
2
3
4
arr := [3]int{1, 2, 3}
var arrp *[3]int // 数组的指针
a := &arr // 直接取数组变量的地址赋值会报错(arrp = &arr)
arrp = a // 通过第三个变量传递

指针数组:

1
2
3
4
5
6
arr := [3]*int{}
numArr := [3]int{1, 2, 3}
for i, v := range numArr {
arr[i] = &v
fmt.Println(*arr[i])
}

3、字典的指针

1
2
3
4
5
6
maps := map[string]string{
"name" : "ludis",
"age": "18",
}
var p *map[string]string = &maps // 字典可直接取地址赋值给指针变量,不同于数组,需要通过中间变量
fmt.Println((*p)["name"]) // 取值时*指针变量需要括号括起来

4、函数的指针与指针函数

函数的指针:

1
2
3
4
5
6
7
8
9
package main

import "fmt"

func main {
fmt.Println(add) // 0x1093c40
}

func add() {}
  • 函数声明后,函数名变量本身就是指针类型,存储的是指向函数体的地址。
  • 因此当对函数变量赋值给其他变量时,属于浅拷贝,只是拷贝指向函数的地址。

指针函数:指针函数与结构体方法类似,见下。

5、 结构体的指针

结构体创建对象:

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
31
32
33
34
35
36
package main

import "fmt"

type Person struct {
name string
age string
}

func main() {
// var关键字声明对象
var person1 = Person{
"佩奇",
"3",
}
// := 简写声明
person2 := Person{
"佩奇粑粑",
"28",
}
// new关键字声明
var person3 = new(Person) // 等同于 person3 := &Person{"佩奇麻麻", "26"}
person3.name = "佩奇麻麻"
person3.age = "26"

fmt.Println(person1, person2, person3) // {佩奇 3} {佩奇粑粑 28} &{佩奇麻麻 26}

p1 := person1
p2 := person2
p3 := person3
p1.name = "猪宝宝"
p1.name = "猪爹"
p1.name = "猪妈"
fmt.Println(person1, person2, person3) // {佩奇 3} {佩奇粑粑 28} &{猪妈 26}
}

从结果可以看出:

  • 前两种声明方式创建,变量中直接存储的是对象,对其进行拷贝为深拷贝。
  • 使用new创建,变量中存储的是地址,对其拷贝为浅拷贝。

结构体的方法:

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
31
32
33
34
35
package main

import "fmt"

type Person struct {
name string
age int
}

func (p Person) setName() {
p.name = "小猪佩奇"
}

func (p *Person) setAge(age int) {
p.age = age
}

func main() {
// var关键字声明对象, 等同于:=声明
var person = Person{"佩奇", 3}
fmt.Println(person.name, person.age) // 佩奇 3
person.setName()
person.setAge(6)
fmt.Println(person.name, person.age) // 佩奇 6
// new 声明
pigone := new(Person) // 🌚 not pgone
pigone.name = "pig"
pigone.age = 69
fmt.Println(pigone) // &{pig 69}
pigone.setName()
pigone.setAge(96)
fmt.Println(pigone) // &{pig 96}

}

由结果可知:

  • 结构体的方法,如果传入的值为对象类型时(setName声明方式),不管传入的是值类型(对象)还是引用类型(指针),在方法中都会深拷贝传入的对象,修改值后传入的对象不收影响。
  • 如果结构体方法传传参类型为指针类型时(setAge声明方式),不管传入的是什么类型,都属于浅拷贝,修改值影响传入的对象。

6、interface 接口

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
31
32
package main

import "fmt"

// 结构体
type Person struct {
name string
age int
}

// 结构体方法
func (p Person) fun1 {
p.name = "大猪"
}

func (p *Person) fun2 {
p.name = "小猪"
}

// 接口
type PersonInfo interface {
fun1()
fun2()
}

func main() {
person := Person{"猪猪侠", 9}
person1 := new(Person)
var p PersonInfo = person // 报错
var p PersonInfo = &person // 正确
var p PersonInfo = person1 // 正确
}

结论:

  • 声明接口时,接口中的函数必须在结构体中有声明
  • 当结构体的方法中,有一个(最少一个)是引用类型(传递指针)的方法时,那么给接口变量赋值时,必须使用引用类型!

END🤔

Author

Ludis

Posted on

2018-01-27

Updated on

2018-02-13

Licensed under

Comments