上卷 程序设计
中卷 标准库
- bufio 1.18
- bytes 1.18
- io 1.18
- container 1.18
- encoding 1.18
- crypto 1.18
- hash 1.18
- index 1.18
- sort 1.18
- context 1.18
- database 1.18
- connection
- query
- queryrow
- exec
- prepare
- transaction
- scan & null
- context
- tcp
- udp
- http
- server
- handler
- client
- h2、tls
- url
- rpc
- exec
- signal
- embed 1.18
- plugin 1.18
- reflect 1.18
- runtime 1.18
- KeepAlived
- ReadMemStats
- SetFinalizer
- Stack
- sync 1.18
- atomic
- mutex
- rwmutex
- waitgroup
- cond
- once
- map
- pool
- copycheck
- nocopy
- unsafe 1.18
- fmt 1.18
- log 1.18
- math 1.18
- time 1.18
- timer
下卷 运行时
源码剖析
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
5.6 指针
不能将内存 地址 与 指针 混为一谈。
地址是内存中每个字节单元的唯一编号,而指针则是实体。指针需分配内存空间,相当于一个专门用来保存地址的整型变量。
x: int p: *int -------+---------------+--------------+------- ... | 100 | 0xc000000000 | ... memory -------+---------------+--------------+------- 0xc000000000 0xc000000008 address 提示:为便于阅读,地址假定。
func main() { var x int var p *int = &x *p = 100 println(p, *p) }
- 取址运算符
&
用于获取目标地址。 - 指针运算符
*
间接引用目标对象。 - 二级指针
**T
,含包名则写成**package.T
。
- 指针默认值
nil
,支持==
、!=
操作。 - 不支持指针运算,可借助
unsafe
变相实现。
func main() { // 空指针也会分配内存。 var p *int println(unsafe.Sizeof(p)) // 8 /* p: *int +--------------+ | 0 | +--------------+ 0xc000000008 */ var x int /* p: *int x: int +---------------+ +---------------+ | 0 | | 0 | +---------------+ +---------------+ 0xc000000008 0xc000000000 */ // 二级指针,指针的指针。 var pp **int = &p *pp = &x /* +--------- *p -----------+ | | pp: **int p | x v +---------------+ +---------------+ +---------------+ | 0xc000000008 -|----->| 0xc000000000 -|----->| 0 | +---------------+ +---------------+ +---------------+ 0xc000000010 0xc000000008 ^ 0xc000000000 ^ | | | +-------- *pp ------------------+ | | | +-------- **pp ----------------------------------------+ */ *p = 100 **pp += 1 println(**pp, *p, x) // 101, 101, 101 }
并非所有对象都能进行取址操作。
func main() { m := map[string]int{ "a": 1, } // _ = &m["a"] // ~~~~~~~ invalid: cannot take address of m["a"] }
支持相等运算符,但不能做加减法运算,不能做类型转换。
如两个指针指向同一地址,或都为 nil
,那么它们相等。
func main() { var b byte var p *byte = &b // p++ // ~~~ invalid: p++ (non-numeric type *byte) // n := (*int)(p) // ~~~~~~ cannot convert *byte to *int }
func main() { var p1, p2 *int println(p1 == p2) // true var x int p1, p2 = &x, &x println(p1 == p2) // true var y int p2 = &y println(p1 == p2) // false }
指针没有专门指向成员的 ->
运算符,统一使用 .
选择表达式。
func main() { a := struct { x int }{ 100 } p := &a p.x += 100 println(p.x) // 200 }
零长度(0 byte)对象指针是否相等,与版本及编译优化有关,不过肯定不等于 nil
。
func main() { var a, b struct{} var c [0]int pa, pb, pc := &a, &b, &c println(pa, pb, pc) println(pa == nil || pc == nil) println(pa == pb) } /* $ go build -gcflags "-N -l" && ./test 0xc00009cf56 0xc00009cf56 0xc00009cf50 false true $ go build && ./test 0xc000088f70 0xc000088f70 0xc000088f70 false false */
借助 unsafe
实现指针转换和运算,须自行确保内存安全。
- 普通指针:
*T
,包含类型信息。 - 通用指针:
Pointer
,只有地址,没有类型。 - 指针整数:
uintptr
,足以存储地址的整数。
func main() { d := [...]int{1, 2, 3} p := &d // *[3]int --> *int p2 := (*int)(unsafe.Pointer(p)) // p2++ p2 = (*int)(unsafe.Add(unsafe.Pointer(p2), unsafe.Sizeof(p[0]))) *p2 += 100 fmt.Println(d) // [1 102 3] }
普通指针( *T
)和通用指针( Pointer
)都能构成引用,影响垃圾回收。
而 uintptr
只是整数,不构成引用关系,无法阻止垃圾回收器清理目标对象。
有关 unsafe
更多信息,请阅读《中卷:标准库,语言》章节。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论