指针
指针是一个变量,其值为另一个变量的地址,即,内存地址。
指针类型的数据大小为固定值,32位系统为4字节,64位系统为8字节。
1、指针的定义和使用
取址符号:&
指针:*
传过去一个地址,通过指针进行接收
定义一个指针:
var a int = 10
var p *int = &a
// 定义了一个指针,p的类型为*int,p指向a的地址
//通过指针修改值
*p = 20
fmt.Println(a) //20
不同于C/C++语言中的指针,go语言中的指针限制了指针的运算,不能通过修改指针运算的方式访问其他内存的值
但是go语言在unsafe包中提供了一些方法,可以通过指针运算的方式访问其他内存的值,但是这种方式是不安全的,不建议使用。
2、指针的初始化
指针未初始化时,默认值为nil
在定义指针时需要进行初始化
下面是几种指针初始化写法,按需要选择,不是全部贴进同一个作用域:
var a int = 10
var p *int = &a
var p2 = new(int) //new函数返回一个指针,指向一个新的int类型的值,值为0
// 如果是结构体还能用下面的方式
p := &Person{}
取已有变量地址可以用 &,需要新零值对象时可以用 new;也可以用 &Person{} 这样的写法。
map、slice、channel的初始化最好使用make方式
需要解引用时,指针必须指向有效对象。nil map 可以读取,但写入前必须初始化。
3、swap与指针
func swap(a, b *int) {
t := *a
*a = *b
*b = t
}
func main() {
var a int = 10
var b int = 20
swap(&a, &b)
fmt.Println(a, b) //20 10
}
4、Go 中的 nil
nil 是指针、切片、map、channel、函数和接口等类型可以具有的零值。它不是所有类型的统一零值:整数是 0,布尔值是 false,结构体的零值则是每个字段各自的零值。
这里有两点容易记错:nil slice 可以 append;nil map 可以读,但不能直接写。
package main
import "fmt"
func main() {
var nums []int
nums = append(nums, 1)
fmt.Println(nums) // [1]
var counts map[string]int
fmt.Println(counts["go"]) // 0
// counts["go"] = 1 // nil map 写入会 panic
counts = make(map[string]int)
counts["go"] = 1
fmt.Println(counts["go"]) // 1
}
空切片和 nil 切片的长度都可以是 0,但 slice == nil 的结果不同;切片也不能像两个整数那样直接互相用 == 比较。
另外,接口里装着一个有类型的 nil 指针时,接口本身可能不等于 nil。以后处理 error 返回值时也要注意这一点,不能只把 nil 理解成“任何东西都是空的”。
规则可以对照 Go 规范:append、索引表达式和零值。