Golang基础进阶——指针
变量和内存地址
每个变量都有内存地址,可以理解为变量来操作对应的内存,go语言的取地址符是&,放到一个变量前使用就会返回相应变量的内存地址,&符跟指针类型息息相关:
func main() {
var a int = 10
fmt.Printf("变量地址:%x
", &a)
}
指针类型介绍
指针类型,变量存的是一个地址,这个地址存的才是值
获取指针类型所指向的值,使用 *。示例:
func main(){
var a int
var p *int
// 指针只能存储地址否则报错, &a表示取a的地址存储到p
p = &a
// p存储的是a的内存地址,取出a地址指向的值就得需要加*,才能从地址中取值
fmp.Println(*p)
fmp.Println(p)
}
值类型和引用类型
- 值类型:int、float、bool、array、struct、string这些类型都属于值类型,使用这些类型的变量直接指向存在内存中的值,值类型的变量的值存储在栈中。当使用等号=将一个变量的值赋给另一个变量时,如 j = i ,实际上是在内存中将 i 的值进行了拷贝。特点:变量直接存储值,内存通常在栈中分配,栈在函数调用完会被释放
- 引用类型:特指指针、slice、map、channel这三种预定义类型。引用类型拥有更复杂的存储结构:(1)分配内存 (2)初始化一系列属性等一个引用类型的变量r1存储的是r1的值所在的内存地址(数字),或内存地址中第一个字所在的位置,这个内存地址被称之为指针,这个指针实际上也被存在另外的某一个字中。特点:变量存储的是一个地址,这个地址存储最终的值。内存通常在堆上分配,通过GC回收。
var 指针变量名 *指针类型
示例:
func main() {
var a int = 20
var ip *int
// 指针存地址
ip = &a
// %x 以十进制方式表示
fmt.Printf("a的地址:%x
", &a)
fmt.Printf("ip变量的值:%x
", ip)
fmt.Printf("ip指向的变量的值:%d
", *ip)
}
空指针
当一个指针被定义后没有分配到任何变量时,它的值为 nil
func main() {
var p *int
fmt.Println(p)
fmt.Printf("p的值 %x
", p)
}
值传递和引用传递
示例1:
func swap(a, b *int) {
fmt.Println(a, b)
*a, *b = *b, *a
}
func main() {
a, b := 3, 4
swap(&a, &b)
fmt.Println(a, b)
}
示例2:
func swap(a, b *int) (*int, *int) {
a, b = b, a
return a, b
}
func main() {
a, b := 3, 4
c, d := swap(&a, &b)
fmt.Println(*c, *d)
a = *c
// *d 指向 a,a更改为4,所以*d也更改为4
b = *d
fmt.Println(a, b)
}

new()和make()
- make()用来分配引用类型的内存,例如slice、map、channel,并且初始化内存
- new()用来分配各种类型的内存,但它不会初始化内存,创建之后是一个指针类型
- make()的用途不同于new(),它只能创建slice、map、channel,并返回类型为T(非指针)的已初始化(非零值)的值
示例:
func main() {
p := new(int)
fmt.Println(p) // 0xc000054080
fmt.Println(*p) // 0
fmt.Printf("%T
", p) // *int
m := make([]int, 10, 50)
fmt.Println(m)
}