Go基础|第6章:pointer

Synopsis: Go 语言提供了指针。指针是一种直接存储了值的内存地址的数据类型。& 操作符可以返回一个变量的内存地址,并且 * 操作符 可以获取指针指向的变量内容,但是在 Go 语言里没有指针运算
1. 指针类型
A pointer is a variable that contains the address
of a value.
对于每一个变量必然有对应的内存地址(变量有时候也被称为可寻址的值),通过 指针
我们可以直接读取或更新对应变量的值,而无需知道该变量的名字。Go 语言使用 值传递
,如果考虑效率的话,较大的 struct 通常会用 指针
的方式传递给函数形参和返回
*T
类型表示指向 T 类型值的 指针
,其零值为 nil
:
指向不同类型的指针不能互相比较:
var p1 *int var p2 *float32 fmt.Println(p1 == p2) // invalid operation: p1 == p2 (mismatched types *int and *float32)
或赋值:
package main import ( "fmt" ) func main() { var p1 *int var p2 *float32 i := 10 p1 = &i fmt.Printf("%T, %#v \n", p1, p1) // p2 = p1 // cannot use p1 (type *int) as type *float32 in assignment fmt.Printf("%T, %#v", p2, p2) } /* Output: *int, (*int)(0xc0000100a0) *float32, (*float32)(nil) */
2. 地址操作符: &
&
操作符会生成一个指向其操作数的指针:
package main import "fmt" func main() { i := 10 p := &i // 指针 p 指向 i fmt.Printf("%T, %v", p, p) } /* Output: *int, 0xc00000a0b8 */
3. 间接引用操作符: *
*
操作符表示指针指向的变量的值:
当使用指针修改变量时,所有使用该变量的地方都会看到变化。另外,与 C 不同,Go 没有指针运算
4. new() 函数创建指针
创建指针的方式除了
和
以外,还可以使用内建函数 new(T)
,它会创建 T 类型的匿名变量(初始化为 T 类型的零值),并返回变量地址:
// The new built-in function allocates memory. The first argument is a type, // not a value, and the value returned is a pointer to a newly // allocated zero value of that type. func new(Type) *Type
package main import "fmt" func main() { var p = new(int) fmt.Printf("%T, %v \n", p, p) fmt.Printf("*p 表示指针 p 所指向的变量的值: %T, %v", *p, *p) } /* Output: *int, 0xc00000a0b8 *p 表示指针 p 所指向的变量的值: int, 0 */
5. panic: nil pointer dereference
由于 *T
类型指针 p 的零值为 nil
,此时执行 *p
将导致运行时 panic 异常:
package main import ( "fmt" ) func main() { var p *int fmt.Printf("%T, %#v\n", p, p) // Output: *int, (*int)(nil) *p = 10 // 想通过指针 p 设置值,panic: runtime error: invalid memory address or nil pointer dereference fmt.Printf("%T, %#v", p, p) }
可以修改为:
package main import ( "fmt" ) func main() { var i int var p *int fmt.Printf("%T, %#v\n", p, p) p = &i // p is no longer nil fmt.Println(i) fmt.Printf("%T, %#v\n", p, p) *p = 10 fmt.Println(i) fmt.Printf("%T, %#v", p, p) } /* Output: *int, (*int)(nil) 0 *int, (*int)(0xc000014098) 10 *int, (*int)(0xc000014098) */
6. 指针比较
任何类型的指针的零值都是 nil
:
package main import ( "fmt" ) func main() { var p1, p2 *int var p3 *float64 fmt.Printf("%T, %#v \n", p1, p1) fmt.Printf("%T, %#v \n", p2, p2) fmt.Printf("%T, %#v \n\n", p3, p3) fmt.Println(p1 == nil) fmt.Println(p2 == nil) fmt.Println(p3 == nil) } /* Output: *int, (*int)(nil) *int, (*int)(nil) *float64, (*float64)(nil) true true true */
但是一旦指针 p 指向了某个有效的变量时,那么 p == nil 表达式的值为 false:
package main import ( "fmt" ) func main() { var p1, p2 *int var p3 *float64 fmt.Printf("%T, %#v \n", p1, p1) fmt.Printf("%T, %#v \n", p2, p2) fmt.Printf("%T, %#v \n\n", p3, p3) a, b := 0, 0 // a 和 b 的值相同,但内存地址不同 c := 3.14 p1 = &a // 指针指向了有效变量后就不是 nil 了 p2 = &b p3 = &c fmt.Printf("%T, %#v \n", p1, p1) fmt.Printf("%T, %#v \n", p2, p2) fmt.Printf("%T, %#v \n\n", p3, p3) fmt.Println(p1 == nil) fmt.Println(p2 == nil) fmt.Println(p3 == nil) } /* Output: *int, (*int)(nil) *int, (*int)(nil) *float64, (*float64)(nil) *int, (*int)(0xc0000a0068) *int, (*int)(0xc0000a0080) *float64, (*float64)(0xc0000a0088) false false false */
指针之间可以进行相等测试(必须是相同的 *T
),只有当它们 指向同一个变量 或 全部是 nil
时才相等:
package main import ( "fmt" ) func main() { var x, y int // x 和 y 都被初始化整形的零值 0,但内存地址不同 p1 := &x // 指针指向了有效变量后就不是 nil 了 p2 := &y fmt.Printf("%T, %#v \n", p1, p1) fmt.Printf("%T, %#v \n\n", p2, p2) fmt.Println(p1 == &x) // 指向同一个变量,或者 fmt.Println(&x == &x) fmt.Println(&x == &y) // 或者 fmt.Println(p1 == p2) fmt.Println(p1 == nil) // 或者 fmt.Println(&x == nil) } /* Output: *int, (*int)(0xc0000a0068) *int, (*int)(0xc0000a0080) true false false */
分享
相关推荐
作者

0 条评论
评论者的用户名
评论时间暂时还没有评论.