bl双性强迫侵犯h_国产在线观看人成激情视频_蜜芽188_被诱拐的少孩全彩啪啪漫画

slice是如何擴容的

本篇內容介紹了“slice是如何擴容的”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

創新互聯是一家專業提供天祝藏族自治企業網站建設,專注與做網站、網站設計html5、小程序制作等業務。10年已為天祝藏族自治眾多企業、政府機構等服務。創新互聯專業網站制作公司優惠進行中。

問題1,slice的底層數據結構

我擦,這么直接的嘛?

我猜是數組加鏈表,結果猜錯了0分。

翻看源碼。

runtime/slice.go

type slice struct {
	array unsafe.Pointer  //數據結構是簡單粗暴的數組指針
	len   int
	cap   int
}

問題2,slice是如何擴容的

又猜錯了~

還是繼續看源碼吧

從源碼找了半天,發現一個這。

growslice handles slice growth during append.

so,就是你了。

func growslice(et *_type, old slice, cap int) slice { // 第三個cap,新的最小容量
	//巴拉巴拉巴拉 一堆判斷

	newcap := old.cap  //變量存儲空間大小
	doublecap := newcap + newcap  //雙倍空間大小
	if cap > doublecap {  //如果歷史空間大于雙倍的容量,新的最小容量
		newcap = cap
	} else {
		//如果長度小于 1024  新長度就是2倍老容量
		if old.len < 1024 {
			newcap = doublecap
		} else {
			//當大于1024 走公式   newcap += newcap / 4,直到newcap大于等于老cap
			for 0 < newcap && newcap < cap {
				newcap += newcap / 4
			}
			if newcap <= 0 {
				newcap = cap
			}
		}
	}

	var overflow bool
	var lenmem, newlenmem, capmem uintptr
	//對et的size做匹配,獲取需要申請的空間大小
	//1 不處理直接分配
	//系統指針大小 進行計算和位運算
	//2 唯一運算
	//默認 相乘
	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 == sys.PtrSize:
		lenmem = uintptr(old.len) * sys.PtrSize
		newlenmem = uintptr(cap) * sys.PtrSize
		capmem = roundupsize(uintptr(newcap) * sys.PtrSize)
		overflow = uintptr(newcap) > maxAlloc/sys.PtrSize
		newcap = int(capmem / sys.PtrSize)
	case isPowerOfTwo(et.size):
		var shift uintptr
		if sys.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)
	}

	//如果append一次超過過多的元素新增,直接報錯,越界,超出容量大小
	if overflow || capmem > maxAlloc {
		panic(errorString("growslice: cap out of range"))
	}

	var p unsafe.Pointer //申請新的內存,并把指針指向p
	if et.ptrdata == 0 {
		p = mallocgc(capmem, nil, false)
		memclrNoHeapPointers(add(p, newlenmem), capmem-newlenmem)
	} else {
		p = mallocgc(capmem, et, true)
		if lenmem > 0 && writeBarrier.enabled {
			bulkBarrierPreWriteSrcOnly(uintptr(p), uintptr(old.array), lenmem)
		}
	}
	//將老的數據移動到新的數據
	memmove(p, old.array, lenmem)

	return slice{p, old.len, newcap}
}

總結

其實可以看出,golang的切片擴容是比較粗暴的,直接賦值拷貝。不過,golang區分的長度和容量兩種單位計量,一般會提前分配足夠的cap,可以減少maclloc的次數。

“slice是如何擴容的”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注創新互聯網站,小編將為大家輸出更多高質量的實用文章!

文章題目:slice是如何擴容的
文章來源:http://vcdvsql.cn/article26/gghjjg.html

成都網站建設公司_創新互聯,為您提供手機網站建設網站營銷網站導航網站制作移動網站建設外貿網站建設

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

商城網站建設