#1

# 数组与切片

• 切片s1 := a[:5]，切片和数组对应关系：

Go-slice-2020-05-12-15-23-13
• 切片s2 := a[3:6]，切片和数组对应关系：

Go-slice-2020-05-12-15-44-43

# 指向同一个底层数组的切片修改值

``````import (
"fmt"
"testing"
)

func TestSliceShareMemory(t *testing.T) {
year := []string{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}
Q2 := year[3:6]
t.Log(Q2, len(Q2), cap(Q2))
summer := year[5:8]
t.Log(summer, len(summer), cap(summer))
summer[0] = "Unkonw"
t.Log(Q2)
t.Log(year)
}
// === RUN   TestSliceShareMemory
//     TestSliceShareMemory: slice_test.go:36: [Apr May Jun] 3 9
//     TestSliceShareMemory: slice_test.go:38: [Jun Jul Aug] 3 7
//     TestSliceShareMemory: slice_test.go:40: [Apr May Unkonw]
//     TestSliceShareMemory: slice_test.go:41: [Jan Feb Mar Apr May Unkonw Jul Aug Sep Oct Nov Dec]
// --- PASS: TestSliceShareMemory (0.00s)
// PASS
``````

# 切片表达式

1. 切片len()是可访问长度，容量cap()是总空间大小。通过数组生成的切片， len为首尾索引之差，cap为从切片首索引到数组末尾长度
2. 切片s[low:high:max]，从切片s的low处到high处所获得的切片，len=high-low，cap=max-low
``````func TestSliceExpression(t *testing.T) {
a := [5]int{1, 2, 3, 4, 5}
// b := a[1:3:7]
b := a[1:3:5]
fmt.Printf("b:%v len(b):%v cap(b):%v\n", b, len(b), cap(b))
}
// === RUN   TestSliceExpression
// b:[2 3] len(b):2 cap(b):4
// --- PASS: TestSliceExpression (0.00s)
// PASS
``````

# 切片不能比较

``````func TestSliceCompare(t *testing.T) {
a := []int{1, 2, 3, 4}
b := []int{1, 2, 3, 4}
if a == b {
t.Log("a==b")
}
}
// invalid operation: a == b (slice can only be compared to nil)
// FAIL go_learn/go_test/slice_test [build failed]
// FAIL
``````

# 切片的append

## 计算逻辑newcap

1. new cap > old * 2直接申请新容量大小;
2. 小于2倍时，len<1024翻倍，len>1024加上1/4
``````//\$GOROOT/src/runtime/slice.go
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
}
}
}

//...略
lenmem = uintptr(old.len)
newlenmem = uintptr(cap)
capmem = roundupsize(uintptr(newcap))
overflow = uintptr(newcap) > maxAlloc
newcap = int(capmem)
//...略
``````

## 实际申请内存大小

``````//\$GOROOT/src/runtime/msize.go
// Returns size of the memory block that mallocgc will allocate if you ask for the size.
func roundupsize(size uintptr) uintptr {
if size < _MaxSmallSize {
if size <= smallSizeMax-8 {
return uintptr(class_to_size[size_to_class8[(size+smallSizeDiv-1)/smallSizeDiv]])
} else {
return uintptr(class_to_size[size_to_class128[(size-smallSizeMax+largeSizeDiv-1)/largeSizeDiv]])
}
}
if size+_PageSize < size {
return size
}
return alignUp(size, _PageSize)
}
``````

`roundupsize()`中的class_to_size、size_to_class8是存了具体大小的数组，根据传入的newcap来算出下标，拿到对应的大小值。这些数组在`//\$GOROOT/src/runtime/sizeclasses.go`，这个文件又是`//\$GOROOT/src/runtime/mksizeclasses.go.go`生成的，生成规则就先不去看了。

``````//\$GOROOT/src/runtime/sizeclasses.go
// Code generated by mksizeclasses.go; DO NOT EDIT.
//go:generate go run mksizeclasses.go
var class_to_size = [_NumSizeClasses]uint16{0, 8, 16, 32, 48, 64, 80, 96, 112, 128 ...}

var size_to_class8 = [smallSizeMax/smallSizeDiv + 1]uint8{0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25 ...}
``````

``````func TestSliceAppend(t *testing.T) {
var a = make([]int, 5, 10)
for i := 0; i < 10; i++ {
a = append(a, i)
fmt.Printf("a ptr: %p\n", a)
}
fmt.Println(a)
}
// === RUN   TestSliceAppend
// a ptr: 0xc00000c320
// a ptr: 0xc00000c320
// a ptr: 0xc00000c320
// a ptr: 0xc00000c320
// a ptr: 0xc00000c320
// a ptr: 0xc0000100a0
// a ptr: 0xc0000100a0
// a ptr: 0xc0000100a0
// a ptr: 0xc0000100a0
// a ptr: 0xc0000100a0
// [0 0 0 0 0 0 1 2 3 4 5 6 7 8 9]
// --- PASS: TestSliceAppend (0.00s)
// PASS

func TestSliceAppend2(t *testing.T) {
s := []int{1, 2, 3, 4}
a := make([]int, 3, 6)
b := append(a, 10)
a[0] = 50
fmt.Printf("a: %v\tptr: %p\tfirst: %v\n", a, a, a[0])
fmt.Printf("b: %v\tptr: %p\tfirst: %v\n", b, b, b[0])

b = append(a, s...)
a[0] = 100
fmt.Printf("a: %v\tptr: %p\tfirst: %v\n", a, a, a[0])
fmt.Printf("b: %v\tptr: %p\tfirst: %v\n", b, b, b[0])
}
// === RUN   TestSliceAppend2
// a: [50 0 0]  ptr: 0xc00000a330   first: 50
// b: [50 0 0 10]   ptr: 0xc00000a330   first: 50
// a: [100 0 0] ptr: 0xc00000a330   first: 100
// b: [50 0 0 1 2 3 4]  ptr: 0xc00001a4e0   first: 50
// --- PASS: TestSliceAppend2 (0.00s)
// PASS

func TestSliceAppend3(t *testing.T) {
a1 := make([]int, 20)
b1 := make([]int, 40)
a1 = append(a1, b1...)
fmt.Println(len(a1), cap(a1))

a2 := make([]int, 20)
b2 := make([]int, 42)
a2 = append(a2, b2...)
fmt.Println(len(a2), cap(a2))
}
// === RUN   TestSliceAppend3
// 60 60
// 62 64
// --- PASS: TestSliceAppend3 (0.00s)
// PASS
``````

# 切片元素删除

``````func TestSliceDelete(t *testing.T) {
a := []int{30, 31, 32, 33, 34, 35, 36, 37}
// 要删除索引为2的元素
a = append(a[:2], a[3:]...)
t.Log(a)
}
// === RUN   TestSliceDelete
//     TestSliceDelete: slice_test.go:98: [30 31 33 34 35 36 37]
// --- PASS: TestSliceDelete (0.00s)
// PASS
``````