Golang slice切片操作之切片的追加、删除、插入等

本文介绍了Golang slice切片操作之切片的追加、删除、插入等,分享给大家,具体如下:

一、一般操作

1,声明变量,go自动初始化为nil,长度:0,地址:0,nil

func main(){
  var ss []string;
  fmt.Printf("length:%v \taddr:%p \tisnil:%v",len(ss),ss, ss==nil)
}

---
Running...

length:0   addr:0x0   isnil:true
Success: process exited with code 0.

2,切片的追加,删除,插入操作

func main(){
  var ss []string;
  fmt.Printf("[ local print ]\t:\t length:%v\taddr:%p\tisnil:%v\n",len(ss),ss, ss==nil)
  print("func print",ss)
  //切片尾部追加元素append elemnt
  for i:=0;i<10;i++{
    ss=append(ss,fmt.Sprintf("s%d",i));
  }
  fmt.Printf("[ local print ]\t:\tlength:%v\taddr:%p\tisnil:%v\n",len(ss),ss, ss==nil)
  print("after append",ss)
  //删除切片元素remove element at index
  index:=5;
  ss=append(ss[:index],ss[index+1:]...)
  print("after delete",ss)
  //在切片中间插入元素insert element at index;
  //注意:保存后部剩余元素,必须新建一个临时切片
  rear:=append([]string{},ss[index:]...)
  ss=append(ss[0:index],"inserted")
  ss=append(ss,rear...)
  print("after insert",ss)
}
func print(msg string,ss []string){
  fmt.Printf("[ %20s ]\t:\tlength:%v\taddr:%p\tisnil:%v\tcontent:%v",msg,len(ss),ss, ss==nil,ss)
  fmt.Println()
}
------
Running...

[ local print ]  :   length:0  addr:0x0  isnil:true
[      func print ]  :  length:0  addr:0x0  isnil:true  content:[]
[ local print ]  :  length:10  addr:0xc208056000  isnil:false
[     after append ]  :  length:10  addr:0xc208056000  isnil:false  content:[s0 s1 s2 s3 s4 s5 s6 s7 s8 s9]
[     after delete ]  :  length:9  addr:0xc208056000  isnil:false  content:[s0 s1 s2 s3 s4 s6 s7 s8 s9]
[     after insert ]  :  length:10  addr:0xc208056000  isnil:false  content:[s0 s1 s2 s3 s4 inserted s6 s7 s8 s9]

Success: process exited with code 0.

3,copy的使用。

在使用copy复制切片之前,要保证目标切片有足够的大小,注意是大小,而不是容量,还是看例子:

func main() {
  var sa = make ([]string,0);
  for i:=0;i<10;i++{
    sa=append(sa,fmt.Sprintf("%v",i))

  }
  var da =make([]string,0,10);
  var cc=0;
  cc= copy(da,sa);
  fmt.Printf("copy to da(len=%d)\t%v\n",len(da),da)
  da = make([]string,5)
  cc=copy(da,sa);
  fmt.Printf("copy to da(len=%d)\tcopied=%d\t%v\n",len(da),cc,da)
   da = make([]string,10)
  cc =copy(da,sa);
  fmt.Printf("copy to da(len=%d)\tcopied=%d\t%v\n",len(da),cc,da)

}

---
Running...

copy to da(len=0)  []
copy to da(len=5)  copied=5  [0 1 2 3 4]
copy to da(len=10)  copied=10  [0 1 2 3 4 5 6 7 8 9]

从上面运行结果,明显看出,目标切片大小0,容量10,copy不能复制。目标切片大小小于源切片大小,copy就按照目标切片大小复制,不会报错。

二、初始大小和容量

当我们使用make初始化切片的时候,必须给出size。go语言的书上一般都会告诉我们,当切片有足够大小的时候,append操作是非常快的。但是当给出初始大小后,我们得到的实际上是一个含有这个size数量切片类型的空元素,看例子:

func main(){
  var ss=make([]string,10);
  ss=append(ss,"last");
  print("after append",ss)

}
---
Running...

[     after append ]  :  length:11  addr:0xc20804c000  isnil:false  content:[     last]

实际上,此时我们应该先用下标为切片元素负值。但是如果我们既想有好的效率,有想继续使用append函数而不想区分是否有空的元素,此时就要请出make的第三个参数,容量,也就是我们通过传递给make,0的大小和足够大的容量数值就行了。

func main(){
  var ss=make([]string,0,10);
  ss=append(ss,"last");
  print("after append",ss)

}

---
Running...

[     after append ]  :  length:1  addr:0xc20804a000  isnil:false  content:[last]

三、切片的指针。

1,当我们用append追加元素到切片时,如果容量不够,go就会创建一个新的切片变量,看下面程序的执行结果:

func main() {
  var sa []string
fmt.Printf("addr:%p \t\tlen:%v content:%v\n",sa,len(sa),sa);
  for i:=0;i<10;i++{
    sa=append(sa,fmt.Sprintf("%v",i))
    fmt.Printf("addr:%p \t\tlen:%v content:%v\n",sa,len(sa),sa);
  }
  fmt.Printf("addr:%p \t\tlen:%v content:%v\n",sa,len(sa),sa);

}

---
Running ...
addr:0x0     len:0 content:[]
addr:0x1030e0c8     len:1 content:[0]
addr:0x10328120     len:2 content:[0 1]
addr:0x10322180     len:3 content:[0 1 2]
addr:0x10322180     len:4 content:[0 1 2 3]
addr:0x10342080     len:5 content:[0 1 2 3 4]
addr:0x10342080     len:6 content:[0 1 2 3 4 5]
addr:0x10342080     len:7 content:[0 1 2 3 4 5 6]
addr:0x10342080     len:8 content:[0 1 2 3 4 5 6 7]
addr:0x10324a00     len:9 content:[0 1 2 3 4 5 6 7 8]
addr:0x10324a00     len:10 content:[0 1 2 3 4 5 6 7 8 9]
addr:0x10324a00     len:10 content:[0 1 2 3 4 5 6 7 8 9]

//很明显,切片的地址经过了数次改变。

2,如果,在make初始化切片的时候给出了足够的容量,append操作不会创建新的切片:

func main() {
  var sa = make ([]string,0,10);
fmt.Printf("addr:%p \t\tlen:%v content:%v\n",sa,len(sa),sa);
  for i:=0;i<10;i++{
    sa=append(sa,fmt.Sprintf("%v",i))
    fmt.Printf("addr:%p \t\tlen:%v content:%v\n",sa,len(sa),sa);
  }
  fmt.Printf("addr:%p \t\tlen:%v content:%v\n",sa,len(sa),sa);

}
addr:0x10304140     len:0 content:[]
addr:0x10304140     len:1 content:[0]
addr:0x10304140     len:2 content:[0 1]
addr:0x10304140     len:3 content:[0 1 2]
addr:0x10304140     len:4 content:[0 1 2 3]
addr:0x10304140     len:5 content:[0 1 2 3 4]
addr:0x10304140     len:6 content:[0 1 2 3 4 5]
addr:0x10304140     len:7 content:[0 1 2 3 4 5 6]
addr:0x10304140     len:8 content:[0 1 2 3 4 5 6 7]
addr:0x10304140     len:9 content:[0 1 2 3 4 5 6 7 8]
addr:0x10304140     len:10 content:[0 1 2 3 4 5 6 7 8 9]
addr:0x10304140     len:10 content:[0 1 2 3 4 5 6 7 8 9]

//可见,切片的地址一直保持不变

3, 如果不能准确预估切片的大小,又不想改变变量(如:为了共享数据的改变),这时候就要请出指针来帮忙了,下面程序中,sa就是osa这个切片的指针,我们共享切片数据和操作切片的时候都使用这个切片地址就ok了,其本质上是:append操作亦然会在需要的时候构造新的切片,不过是将地址都保存到了sa中,因此我们通过该指针始终可以访问到真正的数据。

func main() {
  var osa = make ([]string,0);
  sa:=&osa;
  for i:=0;i<10;i++{
    *sa=append(*sa,fmt.Sprintf("%v",i))
    fmt.Printf("addr of osa:%p,\taddr:%p \t content:%v\n",osa,sa,sa);
  }
  fmt.Printf("addr of osa:%p,\taddr:%p \t content:%v\n",osa,sa,sa);

}

---
Running...

addr of osa:0xc20800a220,  addr:0xc20801e020   content:&[0]
addr of osa:0xc20801e0a0,  addr:0xc20801e020   content:&[0 1]
addr of osa:0xc20803e0c0,  addr:0xc20801e020   content:&[0 1 2]
addr of osa:0xc20803e0c0,  addr:0xc20801e020   content:&[0 1 2 3]
addr of osa:0xc208050080,  addr:0xc20801e020   content:&[0 1 2 3 4]
addr of osa:0xc208050080,  addr:0xc20801e020   content:&[0 1 2 3 4 5]
addr of osa:0xc208050080,  addr:0xc20801e020   content:&[0 1 2 3 4 5 6]
addr of osa:0xc208050080,  addr:0xc20801e020   content:&[0 1 2 3 4 5 6 7]
addr of osa:0xc208052000,  addr:0xc20801e020   content:&[0 1 2 3 4 5 6 7 8]
addr of osa:0xc208052000,  addr:0xc20801e020   content:&[0 1 2 3 4 5 6 7 8 9]
addr of osa:0xc208052000,  addr:0xc20801e020   content:&[0 1 2 3 4 5 6 7 8 9]

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 理解Golang中的数组(array)、切片(slice)和map

    我比较喜欢先给出代码,然后得出结论 数组 复制代码 代码如下: package main import (     "fmt" ) func main() {     arr := [...]int{1, 2, 3}     //打印初始的指针     fmt.Printf("the pointer is : %p \n", &arr)     printPointer(arr) } func printPointer(any interface{}) {

  • 浅谈golang slice 切片原理

    slice介绍 数组的长度在定义之后无法再次修改:数组是值类型,每次传递都将产生一份副本.显然这种数据结构无法完全满足开发者的真实需求.在初始定义数组时,我们并不知道需要多大的数组,因此我们就需要"动态数组".在Go里面这种数据结构叫slice,slice并不是真正意义上的动态数组,而是一个引用类型.slice总是指向一个底层array,slice的声明也可以像array一样,只是不需要长度,它是可变长的,可以随时往slice里面加数据. 初看起来,数组切片就像一个指向数组的指针,实际

  • Golang slice切片操作之切片的追加、删除、插入等

    本文介绍了Golang slice切片操作之切片的追加.删除.插入等,分享给大家,具体如下: 一.一般操作 1,声明变量,go自动初始化为nil,长度:0,地址:0,nil func main(){ var ss []string; fmt.Printf("length:%v \taddr:%p \tisnil:%v",len(ss),ss, ss==nil) } --- Running... length:0 addr:0x0 isnil:true Success: process

  • Golang切片Slice功能操作详情

    目录 一.概述 二.切片 2.1 切片的定义 2.2 切片的长度和容量 2.3 切片表达式 简单切片表达式 完整切片表达式 2.4 使用make()函数构造切片 2.5 for range循环迭代切片 2.6 切片的本质 2.7 判断切片是否为空 三.切片功能操作 3.1 切片不能直接比较 3.2 切片的赋值拷贝 3.3 使用copy()函数复制切片 3.4 append()方法为切片添加元素 3.5 从切片中删除元素 从开头位置删除 从中间位置删除 从尾部删除 3.6 切片的扩容策略 一.概述

  • 浅谈Golang Slice切片如何扩容的实现

    目录 一.Slice数据结构是什么? 二.详细代码 1.数据结构 2.扩容原则 3.如何理解扩容规则一 1.当小于1024个元素时 2.当大于1024个元素时 4.如何理解扩容规则二 1.简单理解内存地址更换 总结 一.Slice数据结构是什么? 切片(slice)是 Golang 中一种比较特殊的数据结构,这种数据结构更便于使用和管理数据集合.切片是围绕动态数组的概念构建的,可以按需自动增长和缩小.切片(slice)是可以看做是一个长度可变的数组.切片(slice)自身并不是动态数组或者数组指

  • 详解Python中的__getitem__方法与slice对象的切片操作

    Fib实例虽然能作用于for循环,看起来和list有点像,但是,把它当成list来使用还是不行,比如,取第5个元素: >>> Fib()[5] Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'Fib' object does not support indexing 要表现得像list那样按照下标取出元素,需要实现__getit

  • 轻松读懂Golang中的数组和切片

    目录 一.数组和切片的区别是什么? 1.数组 2.切片 二.数组和切片的初始化? 1.数组 2.切片 二.常见问题 1.切片的初始化与追加 2.slice拼接问题 3.new和make的区别 总结 一.数组和切片的区别是什么? 1.数组 数组是内置(build-in)类型,是一组同类型数据的集合,它是值类型,通过从0开始的下标索引访问元素值.在初始化后长度是固定的,无法修改其长度.当作为方法的参数传入时将复制一份数组而不是引用同一指针.数组的长度也是其类型的一部分,通过内置函数len(array

  • Python切片操作去除字符串首尾的空格

    下面通过实例代码给大家分享Python切片操作去除字符串首尾的空格的方法,具体内容如下所示: #利用切片操作,实现一个trim()函数,去除字符串首尾的空格,注意不要调用str的strip()方法 def trim(s): while s[0:1]==' ': s=s[1:] while s[(len(s)-1):len(s)]==' ': s=s[:-1] return s s=input('请输入一个字符串:') print('去除首尾空格后',trim(s)) 知识点: •取一个list或

  • Python切片操作深入详解

    本文实例讲述了Python切片操作.分享给大家供大家参考,具体如下: 我们基本上都知道Python的序列对象都是可以用索引号来引用的元素的,索引号可以是正数由0开始从左向右,也可以是负数由-1开始从右向左. 在Python中对于具有序列结构的数据来说都可以使用切片操作,需注意的是序列对象某个索引位置返回的是一个元素,而切片操作返回是和被切片对象相同类型对象的副本. 如下面的例子,虽然都是一个元素,但是对象类型是完全不同的: >>> alist = [0, 1, 2, 3, 4, 5, 6

  • python 列表的查询操作和切片

    目录 1.列表 2.列表的创建[]或list() 3.定位列表中的元素L[0] 4.查询列表中元素索引L.index() 5.列表的切片操作L[start:stop:step] 6.L[slice(start,stop,step)] 7.in/not in 查询是否包含某个元素,存在返回True 1.列表 列表是python内置的数据结构(列表.元组.字典.集合),相当于数组 列表中所有数据都是按顺序有序排列,列表属于序列类型 列表中的所有数据都有正数和负数的索引,通过指定的索引总能映射到唯一确

  • Python字符串切片操作知识详解

    一:取字符串中第几个字符 print "Hello"[0] 表示输出字符串中第一个字符 print "Hello"[-1] 表示输出字符串中最后一个字符 二:字符串分割 print "Hello"[1:3] #第一个参数表示原来字符串中的下表 #第二个阐述表示分割后剩下的字符串的第一个字符 在 原来字符串中的下标 这句话说得有点啰嗦,直接看输出结果: el 三:几种特殊情况 (1)print "Hello"[:3] 从第一个字

随机推荐