举例
lencapcaplenappend
func main() {
var array [20]int
fmt.Println(array)
slice1 := array[10:11]
fmt.Println(slice1)
fmt.Println(len(slice1))
fmt.Println(cap(slice1))
}
大家可以先在不看答案的情况下来计算一下输出结果,下面是结果
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0]
1
10
不知大家看出上面的结果没,为何是上面这几个输出结果呢?这里让我们尝试从源码的角度来看看输出这个结果的原因。
说明
$GOROOT/src/reflect/value.go
// Slice returns v[i:j].
// It panics if v's Kind is not Array, Slice or String, or if v is an unaddressable array,
// or if the indexes are out of bounds.
func (v Value) Slice(i, j int) Value {
var (
cap int
typ *sliceType
base unsafe.Pointer
)
switch kind := v.kind(); kind {
// ... 省略
case Array:
// ... 省略
tt := (*arrayType)(unsafe.Pointer(v.typ))
cap = int(tt.len) // 把数组的长度当做cap
typ = (*sliceType)(unsafe.Pointer(tt.slice))
base = v.ptr
case Slice:
typ = (*sliceType)(unsafe.Pointer(v.typ))
s := (*unsafeheader.Slice)(v.ptr)
base = s.Data
cap = s.Cap // 如果为slice,则直接取其中结构体中的cap
case String:
// 这个里面的大致思路就是直接取了字符串中的一段数据拷贝后返回回去
// ... 省略
}
// Declare slice so that gc can see the base pointer in it.
var x []unsafe.Pointer
// Reinterpret as *unsafeheader.Slice to edit.
s := (*unsafeheader.Slice)(unsafe.Pointer(&x))
s.Len = j - i // 统一的,不管是array还是slice,len = j - i
s.Cap = cap - i // 由上面计算出来的cap - i 就是新的cap大小
if cap-i > 0 {
s.Data = arrayAt(base, i, typ.elem.Size(), "i < cap")
} else {
// do not advance pointer, to avoid pointing beyond end of slice
s.Data = base
}
fl := v.flag.ro() | flagIndir | flag(Slice)
return Value{typ.common(), unsafe.Pointer(&x), fl}
}
针对上面代码的一些说明就是:
j-icap-i
经过上面原码的简单说明后,我们再回到上面举例里面的打印输出:
func main() {
var array [20]int
fmt.Println(array) // Output: 这里输出20个0,相信大家问题不大
slice1 := array[10:11]
fmt.Println(slice1) // Output: 经过上面的原码来看,slice1的len=11-10=1,cap=20-10=10,所以输出为[0]
fmt.Println(len(slice1)) // Output: 上面给出了解释,输出为 len=11-10=1
fmt.Println(cap(slice1)) // Output: 上面给出了解释,输出为 cap=20-10=10
}
array[10:11:20]func (v Value) Slice3(i, j, k int) ValueijkSlice