指针概念
一个指针可以指向任何一个值的内存地址。
它指向那个值的内存地址,在 32 位机器上占用 4 个字节,在 64 位机器上占用 8 个字节,并且与它所指向的值的大小无关。
Go语言指针
在Go语言中,直接砍掉了 C 语言指针最复杂的指针运算部分,只留下了获取指针(&运算符)和获取对象(*运算符)的运算,用法和C语言很类似。但不同的是,Go语言中没有->操作符来调用指针所属的成员,而与一般对象一样,都是使用.来调用。
Go 语言中一个指针被定义后没有分配到任何变量时,它的值为 nil。
Go 语言自带指针隐式解引用 :对于一些复杂类型的指针, 如果要访问成员变量时候需要写成类似*p.field的形式时,只需要p.field即可访问相应的成员。
例子讲解
1、使用值作为参数:
func updateValue(val int) {
val = val + 100
}
func main() {
val := 1000
updateValue(val) // 按值传递,传递的是变量的副本
fmt.Println(“val:”, val) // 1000
}
2、使用指针作为参数:
func updateValue(someVal *int) {
*someVal = *someVal + 100
}
func main() {
val := 1000
updateValue(&val) // 按指针传递,不是副本
fmt.Println(“val:”, val) // 1100
}
new函数
使用 new 函数给一个新的结构体变量分配内存,它返回指向已分配内存的指针:
var t *T = new(T)
t := new(T)
变量 t 是一个指向 T的指针,此时结构体字段的值是它们所属类型的零值。
注意:
用new(structName):这个方法得到的是*structName类型,即类的指针类型;
用structName{init para}:这个方法得到的是structName类型,即类的实例类型,不是指针。
示例代码如下:
func updateValue(someVal *int, someVal2 *float64) {
*someVal = *someVal + 100
*someVal2 = *someVal2 + 1.75
}
func main() {
val := 1000
val2 := new(float64)
updateValue(&val, val2)
fmt.Println(“val:”, val) // 1100
fmt.Println(“val2:”, *val2) // 1.75
}
type Student struct {
name string
age int
weight float32
score []int
}
func main(){
pp := new(Student) // 使用 new 关键字创建一个指针
*pp = Student{“Stu”, 23, 65.0, []int{2, 3, 6}} // 实例类型
fmt.Printf(“stu pp1 have %d subjects\n”, len((*pp).score))
fmt.Printf(“stu pp2 have %d subjects\n”, len(pp.score)) //Go语言自带隐式解引用
}
打印输出:
stu pp1 have 3 subjects
stu pp2 have 3 subjects
结构体和指针的综合应用
初始化一个结构体实例,除了上面讲的值类型初始化和结构体指针初始化,还有一种更简短和惯用的方式叫字面量初始化(结构体字面量:struct-literal):
type struct1 struct {
i1 int
f1 float32
str string
}
ms := &struct1{10, 15.5, “Chris”} // 此时ms的类型是 *struct1
混合字面量语法(composite literal syntax)&struct1{a, b, c} 是一种简写,底层仍然会调用new (),这里值的顺序必须按照字段顺序来写。
在下面的例子中能看到可以通过在值的前面放上字段名来初始化字段的方式。
所以归根结底,表达式 new(Type) 和 &Type{}是等价的。
下面的例子显示了一个结构体Person,一个方法,方法有一个类型为 *Person的参数(因此对象本身是可以被改变的),以及三种调用这个方法的不同方式:
type Person struct {
firstName string
lastName string
}
func upPerson(p *Person) {
p.firstName = strings.ToUpper(p.firstName)
p.lastName = strings.ToUpper(p.lastName)
}
func main() {
// 1-struct as a value type:
var pers1 Person
pers1.firstName = “Chris”
pers1.lastName = “Woodward”
upPerson(&pers1)
fmt.Printf(“The name of the person is %s %s\n”, pers1.firstName, pers1.lastName)
// 2—struct as a pointer:
pers2 := new(Person)
pers2.firstName = “Chris”
pers2.lastName = “Woodward”
(*pers2).lastName = “Woodward” // 这是合法的
upPerson(pers2)
fmt.Printf(“The name of the person is %s %s\n”, pers2.firstName, pers2.lastName)
// 3—struct as a literal:
pers3 := &Person{“Chris”,”Woodward”}
upPerson(pers3)
fmt.Printf(“The name of the person is %s %s\n”, pers3.firstName, pers3.lastName)
}
打印输出:
The name of the person is CHRIS WOODWARD
The name of the person is CHRIS WOODWARD
The name of the person is CHRIS WOODWARD
指针的指针
type User struct {
Name string
}
func main() {
u := &User{Name: “Leto”}
fmt.Println(u.Name)
Modify(&u)
fmt.Println(u.Name)
}
func Modify(u **User) {
*u = &User{Name: “Bob”}
}