首页
友情链接
统计
推荐
GitHub
Search
1
蚁群算法学习
541 阅读
2
golang 锁
445 阅读
3
Go 栈和堆
430 阅读
4
GO语言基础plus
386 阅读
5
golang Map
365 阅读
GO
源码阅读
基础
Python
登录
Search
标签搜索
慕课笔记
BeforeIeave
累计撰写
9
篇文章
累计收到
2
条评论
首页
栏目
GO
源码阅读
基础
Python
页面
友情链接
统计
推荐
GitHub
搜索到
6
篇与
的结果
2022-07-27
goalng Slice&String
1 字符串1.1 字符串的源码//runtime 包中的定义 type stringStruct struct { str unsafe.Pointer len int } //reflact 包种的string头部 type StringHeader struct{ Data uintptr Len int //表示的是字节数组的长度,不是字节的数量(遍历中文的时候会出问题) }说明:字符串本质上是一个结构体,str指针指向的是底层的Byte数组。 1.2 字符串的遍历方法一:直接用len(str)作为限制条件,使用for进行访问。最后记得转换为string方法二:直接使用for range的方式进行访问,最后转换为string或用fmt.Printf("%c", each)打印。注意:使用range的时候,会自动解码成rune的形式,由utf8.go文件进行解码。1.3 字符串的切分先将其转为rune数组,再切片,最后转为strings = string([]rune(s)[:3])1.4 注意事项字符串的底层是Byte数组,存在多个字符串的底层共用一个字节内存,所以字符串数不允许更改的。2 切片2.1 切片源码type slice struct { array unsafe.Pointer //指向底层数组的指针 len int //切片引用的长度 cap int //整个切片的大小(容量) }2.2 切片的追加1.不需要扩容的时候:当向切片追加元素时,仅由编译器调整len的大小。2.需要扩容的时候:编译时转为调用runtime.growslice()函数2.3 切片的扩容机制一般情况下,会重新开辟一个两倍长的数组替代原有的数组(因为数组空间必须时连续的),但是如果容量大于目前容量的两倍,则会直接扩容成期望容量的大小。对于过大的切片,会有新的规则,若切片的长度小于1024,则容量会翻倍增长,大于1024则每次仅增加25%的大小。注意切片扩容的时候并发不安全,一定要加锁。2.4 扩容源码阅读func growslice(et *_type, old slice, cap int) slice { if raceenabled { callerpc := getcallerpc() racereadrangepc(old.array, uintptr(old.len*int(et.size)), callerpc, abi.FuncPCABIInternal(growslice)) } if msanenabled { msanread(old.array, uintptr(old.len*int(et.size))) } if asanenabled { asanread(old.array, uintptr(old.len*int(et.size))) } if cap < old.cap { panic(errorString("growslice: cap out of range")) } 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 if cap > doublecap { newcap = cap } else { const threshold = 256 if old.cap < threshold { newcap = doublecap } else { // Check 0 < newcap to detect overflow // and prevent an infinite loop. for 0 < newcap && newcap < cap { // Transition from growing 2x for small slices // to growing 1.25x for large slices. This formula // gives a smooth-ish transition between the two. newcap += (newcap + 3*threshold) / 4 } // Set newcap to the requested cap when // the newcap calculation overflowed. if newcap <= 0 { newcap = cap } } } var overflow bool var lenmem, newlenmem, capmem uintptr // Specialize for common values of et.size. // For 1 we don't need any division/multiplication. // For goarch.PtrSize, compiler will optimize division/multiplication into a shift by a constant. // For powers of 2, use a variable shift. switch { case et.size == 1: lenmem = uintptr(old.len) newlenmem = uintptr(cap) capmem = roundupsize(uintptr(newcap)) overflow = uintptr(newcap) > maxAlloc newcap = int(capmem) case et.size == goarch.PtrSize: lenmem = uintptr(old.len) * goarch.PtrSize newlenmem = uintptr(cap) * goarch.PtrSize capmem = roundupsize(uintptr(newcap) * goarch.PtrSize) overflow = uintptr(newcap) > maxAlloc/goarch.PtrSize newcap = int(capmem / goarch.PtrSize) case isPowerOfTwo(et.size): var shift uintptr if goarch.PtrSize == 8 { // Mask shift for better code generation. shift = uintptr(sys.Ctz64(uint64(et.size))) & 63 } else { shift = uintptr(sys.Ctz32(uint32(et.size))) & 31 } lenmem = uintptr(old.len) << shift newlenmem = uintptr(cap) << shift capmem = roundupsize(uintptr(newcap) << shift) overflow = uintptr(newcap) > (maxAlloc >> shift) newcap = int(capmem >> shift) 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) } // The check of overflow in addition to capmem > maxAlloc is needed // to prevent an overflow which can be used to trigger a segfault // on 32bit architectures with this example program: // // type T [1<<27 + 1]int64 // // var d T // var s []T // // func main() { // s = append(s, d, d, d, d) // print(len(s), "\n") // } if overflow || capmem > maxAlloc { panic(errorString("growslice: cap out of range")) } var p unsafe.Pointer if et.ptrdata == 0 p = mallocgc(capmem, nil, false) // The append() that calls growslice is going to overwrite from old.len to cap (which will be the new length). // Only clear the part that will not be overwritten. memclrNoHeapPointers(add(p, newlenmem), capmem-newlenmem) } else { // Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory. p = mallocgc(capmem, et, true) if lenmem > 0 && writeBarrier.enabled { // Only shade the pointers in old.array since we know the destination slice p // only contains nil pointers because it has been cleared during alloc. bulkBarrierPreWriteSrcOnly(uintptr(p), uintptr(old.array), lenmem-et.size+et.ptrdata) } } memmove(p, old.array, lenmem) return slice{p, old.len, newcap} }
2022年07月27日
232 阅读
0 评论
0 点赞
1
2