Go-切片类型详解(遍历、内存、追加、插入、删除等)_golang 数组头插入数据

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

	panicmakeslicecap()
}

return mallocgc(mem, et, true)

}


![wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==](https://img-blog.csdnimg.cn/2022010612104538251.gif "点击并拖拽以移动")

**切片声明代码** 




var slice []int
slice1 := make([]int,5)
fmt.Println("slice slice1:",slice,slice1)

![wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==](https://img-blog.csdnimg.cn/2022010612104538251.gif "点击并拖拽以移动")

## 声明并初始化


### 一般形式


类似数组,直接写后面花括号里面,代码:




slice2 := []int{1,2,3,4}

![wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==](https://img-blog.csdnimg.cn/2022010612104538251.gif "点击并拖拽以移动")

### 引用数组


给出数组数据




arr := [5]int{5,6,7,8,9}

![wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==](https://img-blog.csdnimg.cn/2022010612104538251.gif "点击并拖拽以移动")

slice[start:end],默认:start=0,end =len(arr)


**代码** 



slice3 := arr[1:]

### 引用切片


和引用数组类似



slice4 := slice3[1:]

切片及数组在内存的情况,请查看后序内存一节。


## 遍历


### for



for i:=0;i<len(slice3);i++{
	fmt.Print(slice3[i]," ")
}

### for range



for _,v := range slice3{
	fmt.Print(v," ")
}

## 内存


查看结构体的具体内容


**src->reflect->type.go**




type SliceHeader struct {
Data uintptr
Len int
Cap int
}


![wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==](https://img-blog.csdnimg.cn/2022010612104538251.gif "点击并拖拽以移动")

编译时创建切片代码


**src->cmd->compile->types**




// NewSlice returns the slice Type with element type elem.
func NewSlice(elem *Type) *Type {
if t := elem.Cache.slice; t != nil {
if t.Elem() != elem {
Fatalf(“elem mismatch”)
}
return t
}

t := New(TSLICE)
t.Extra = Slice{Elem: elem}
elem.Cache.slice = t
return t

}


![wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==](https://img-blog.csdnimg.cn/2022010612104538251.gif "点击并拖拽以移动")


fmt.Printf("&slice1:%p,&slice1[0]:%v\n", &slice1, &slice1[0])
fmt.Printf("&arr:%p &arr[1]:%v &slice3:%p &slice3[0]:%v\n",&arr,&arr[1],&slice3,&slice3[0])
fmt.Printf("&slice4:%p &slice4[0]:%v\n",&slice4,&slice4[0])
arr[2] = 99
fmt.Println("slice3[1] slice4[0]",slice3[1],slice4[0])

 




![](https://img-blog.csdnimg.cn/20210421205050760.PNG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xhZHlfa2lsbGVyOQ==,size_16,color_FFFFFF,t_70)

 slice1内存 
 




![](https://img-blog.csdnimg.cn/20210421205114470.PNG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xhZHlfa2lsbGVyOQ==,size_16,color_FFFFFF,t_70)

 arr、slice3、slice4内存 
 


## 函数/方法


### 长度与容量


len、cap函数获取长度和容量


**代码**



fmt.Println("len(slice3) cap(slice3) len(slice4) cap(slice4):", len(slice3), cap(slice3), len(slice4), cap(slice4))

### 追加与拷贝


append



> 
> func append(slice []Type, elems ...Type) []Type
> 
> 
> 


 内建函数append将元素追加到切片的末尾。若它有足够的容量,其目标就会重新切片以容纳新的元素。否则,就会分配一个新的基本数组。append**返回更新后的切片**,因此必须存储追加后的结果。 


**查看slice增长源代码**


**src->runtime->slice.go**




// growslice handles slice growth during append.
// It is passed the slice element type, the old slice, and the desired new minimum capacity,
// and it returns a new slice with at least that capacity, with the old data
// copied into it.
// The new slice’s length is set to the old slice’s length,
// NOT to the new requested capacity.
// This is for codegen convenience. The old slice’s length is used immediately
// to calculate where to write new values during an append.
// TODO: When the old backend is gone, reconsider this decision.
// The SSA backend might prefer the new length or to return only ptr/cap and save stack space.
func growslice(et *_type, old slice, cap int) slice {
if raceenabled {
callerpc := getcallerpc()
racereadrangepc(old.array, uintptr(old.lenint(et.size)), callerpc, funcPC(growslice))
}
if msanenabled {
msanread(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 {
	if old.cap < 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
		}
	}
}

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 sys.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 == 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)
}

// 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}

}


![wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==](https://img-blog.csdnimg.cn/2022010612104538251.gif "点击并拖拽以移动")



**代码** 



newSlice3 := append(slice3, 110,119)
newSlice4 := append(slice4,slice3...)

### 拷贝



> 
> func copy(dst, src []Type) int
> 
> 
> 


内建函数copy将元素从来源切片复制到目标切片中,也能将字节从字符串复制到字节切片中。c**opy返回被复制的元素数量,它会是 len(src) 和 len(dst) 中较小的那个**。来源和目标的底层内存可以重叠。 


**注意:目标长度放不下时,后序的就不再拷贝了**


**代码**



copy(slice3, slice1)


### 排序



> 
> func Ints(a []int)
> 
> 
> 


Ints函数将a排序为递增顺序。


**代码**



sort.Ints(newSlice3)

### 插入与删除


没有,自己实现,见后面


## 函数传参


### 值传递



func byteInsert(b []byte,index int,data byte) []byte{
//-----索引越界------
if index<0 || index>len(b){
return []byte{}
}
//------前插-------
if index == 0{
return append([]byte{data}, b…)
}
//------尾插-------
if index == len(b){
return append(b, data)
}
//------中间插------
tmp := append(b[:index],data)
return append(tmp,b[index:]…)
}


**使用** 



//-----值传递------
hello := []byte("el")
hello = byteInsert(hello,0,'h')
fmt.Printf("hello:%c\n",hello)
hello = byteInsert(hello,2,'l')
fmt.Printf("hello:%c\n",hello)
hello = byteInsert(hello,4,'o')
fmt.Printf("hello:%c\n",hello)

### 引用传递



func byteDelete(b *[]byte,index int){
//-----索引越界------
if index<0 || index>=len(*b){
return
}
//------前删-------
if index == 0{
*b = (*b)[1:]
return
}
//------尾删-------
if index == len(*b)-1{
*b = (*b)[:len(*b)-1]
return
}
//------中间删------
*b = append((*b)[0:index],(*b)[index+1:]…)
return
}


**使用**



world := []byte("world")
byteDelete(&world,0)
fmt.Printf("world:%c\n",world)
byteDelete(&world,3)

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

:index],(*b)[index+1:]…)
return
}


**使用**



world := []byte("world")
byteDelete(&world,0)
fmt.Printf("world:%c\n",world)
byteDelete(&world,3)

[外链图片转存中…(img-TDns5b4b-1715496680571)]
[外链图片转存中…(img-YjXhj0wc-1715496680571)]
[外链图片转存中…(img-JpEjKI0A-1715496680572)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

  • 9
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值