上卷 程序设计
中卷 标准库
- 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
下卷 运行时
源码剖析
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
8.3 slice
切片底层数组未必在堆上分配。
只要合法,编译器尝试在栈上折腾。
// slice.go type slice struct { array unsafe.Pointer len int cap int }
// slice.go func makeslice(et *_type, len, cap int) unsafe.Pointer // 在堆上分配内存。 mem, overflow := math.MulUintptr(et.size, uintptr(cap)) return mallocgc(mem, et, true) }
扩容
当超出容量(cap)限制时,会引发扩容,重新分配底层数组。
// growslice handles slice growth during append. // It is passed the slice element type, the old slice, and the desired new minimum capacity, // and it returns a new slice with at least that capacity, with the old data // copied into it. func growslice(et *_type, old slice, cap int) slice { if et.size == 0 { // append should not create a slice with nil pointer but non-zero len. // We assume that append doesn't need to preserve old.array in this case. return slice{unsafe.Pointer(&zerobase), old.len, cap} } newcap := old.cap doublecap := newcap + newcap // 如果 cap > 2x,那么按 cap 分配。 // 如果元素 < 1024,那么 2x 分配。 // 如果元素 >= 1024,按 1/4 递增,直到 > cap 申请。 if cap > doublecap { newcap = cap } else { if old.len < 1024 { newcap = doublecap } else { for 0 < newcap && newcap < cap { newcap += newcap / 4 } // Set newcap to the requested cap when // the newcap calculation overflowed. if newcap <= 0 { newcap = cap } } } // 计算内存长度。 switch { case ...: ... default: lenmem = uintptr(old.len) * et.size newlenmem = uintptr(cap) * et.size capmem, overflow = math.MulUintptr(et.size, uintptr(newcap)) capmem = roundupsize(capmem) newcap = int(capmem / et.size) } // 分配新内存,复制数据。 if et.ptrdata == 0 { p = mallocgc(capmem, nil, false) } else { p = mallocgc(capmem, et, true) } memmove(p, old.array, lenmem) return slice{p, old.len, newcap} }
拷贝
从源和目标长度里,选择短的作为要复制数据量。
func slicecopy(toPtr unsafe.Pointer, toLen int, fmPtr unsafe.Pointer, fmLen int, width uintptr) int { // 没有数据要复制。 if fmLen == 0 || toLen == 0 { return 0 } // 选择短的作为复制长度。 n := fmLen if toLen < n { n = toLen } // 如果元素宽度为 0(比如空结构),无需复制。 if width == 0 { return n } size := uintptr(n) * width if size == 1 { *(*byte)(toPtr) = *(*byte)(fmPtr) // known to be a byte pointer } else { memmove(toPtr, fmPtr, size) } return n }
func slicestringcopy(toPtr *byte, toLen int, fm string) int { if len(fm) == 0 || toLen == 0 { return 0 } n := len(fm) if toLen < n { n = toLen } memmove(unsafe.Pointer(toPtr), stringStructOf(&fm).str, uintptr(n)) return n }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论