1. 程式人生 > >【go原始碼分析】go原始碼之slice原始碼分析

【go原始碼分析】go原始碼之slice原始碼分析

Go 語言切片是對陣列的抽象。

Go 陣列的長度不可改變,與陣列相比切片的長度是不固定的,可以追加元素,在追加時可能使切片的容量增大。

len() 和 cap() 函式

    切片是可索引的,並且可以由 len() 方法獲取長度。

    切片提供了計算容量的方法 cap() 可以測量切片最長可以達到多少。

空(nil)切片

    一個切片在未初始化之前預設為 nil,長度為 0

結構體

  slice結構體

    一個指向array地址的指標,slice的長度len和容量cap

type slice struct {
	array unsafe.Pointer
	len   int
	cap   int
}

1. makeslice函式

    呼叫mallocgc分配連續的地址

func makeslice(et *_type, len, cap int) slice {
	// NOTE: The len > maxElements check here is not strictly necessary,
	// but it produces a 'len out of range' error instead of a 'cap out of range' error
	// when someone does make([]T, bignumber). 'cap out of range' is true too,
	// but since the cap is only being supplied implicitly, saying len is clearer.
	// See issue 4085.
	maxElements := maxSliceCap(et.size)
	if len < 0 || uintptr(len) > maxElements {
		panicmakeslicelen()
	}

	if cap < len || uintptr(cap) > maxElements {
		panicmakeslicecap()
	}

	p := mallocgc(et.size*uintptr(cap), et, true)
	return slice{p, len, cap}
}

2. growslice函式

    slice擴大容量函式,這塊可以看出來怎麼增長容量

  •     < 1024,按照兩倍增長
  •     否則按照1.25倍增長
  •     擴容會涉及資料拷貝,產生效能開銷
	newcap := old.cap
	doublecap := newcap + newcap
	if cap > doublecap {
		newcap = cap
	} else {
		if old.len < 1024 {
			newcap = doublecap
		} else {
			// Check 0 < newcap to detect overflow
			// and prevent an infinite loop.
			for 0 < newcap && newcap < cap {
				newcap += newcap / 4
			}
			// Set newcap to the requested cap when
			// the newcap calculation overflowed.
			if newcap <= 0 {
				newcap = cap
			}
		}
	}