golang中切片copy复制和等号复制的区别介绍


Posted in Golang onApril 27, 2021

结论:

copy复制会比等号复制慢。但是copy复制为值复制,改变原切片的值不会影响新切片。而等号复制为指针复制,改变原切片或新切片都会对另一个产生影响。

测试复制速度:

func TestArr1(t *testing.T) {
 var a []int
 for i := 0; i < 100000000; i++ {
  a = append(a, i)
 }
 start := time.Now().UnixNano()
 var b = make([]int, 1000000)
 copy(b, a)
 end := time.Now().UnixNano()
 fmt.Println(end - start)
}

结果为 5001100

func TestArr2(t *testing.T) {
 var a []int
 for i := 0; i < 100000000; i++ {
  a = append(a, i)
 }
 start := time.Now().UnixNano()
 var b = a[0:1000000]
 end := time.Now().UnixNano()
 fmt.Println(end - start)
 _ = b
}

结果为0

结论:

等号复制要比copy赋值速度快

测试更改原切片是否影响新切片:

func TestArr1(t *testing.T) {
 var a []int
 for i := 0; i < 100; i++ {
  a = append(a, i)
 }
 var b = make([]int, 10)
 copy(b, a)
 a[0] = 999
 fmt.Println(b[0])
}

结果0

func TestArr2(t *testing.T) {
 var a []int
 for i := 0; i < 100; i++ {
  a = append(a, i)
 }
 var b = a[0:10]
 a[0] = 999
 fmt.Println(b[0])
}

结果 999

结论:

copy为值复制,更改原切片不会影响新切片,而等号复制相反

补充:go语言,切片研究,容量,长度,复制,追加

今天学习了数组和切片,感觉数组不够灵活,一旦创建,无法添加成员。但是切片就灵活多了,感觉切片存在两种形态,第一种是映射数组来的,那么数组数据变化后,切片数据也变化,h j为映射切片 ,第二 种是独立切片,切片独立创建,并不依赖于任何数组, x y z均为独立切片,z拷贝自y,当y数据改变时,z不受影响。

另外发现个有趣的事,就是切片容量 len,x刚创建时,容量是10,长度是10,增加一个成员后,容量变成20,长度变成11,说明append函数,在增加成员的时候,会大幅度增加容量,但是再看y,它采用循环增加成员的方式创建,创建完成后,长度是10,容量是16。

代码:

var ar = [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
    var h, j []byte
    h = ar[2:5]
    j = ar[0:8]
    ar[2] = 'q'
    fmt.Println(string(h))
    fmt.Println(string(j))
    fmt.Printf("j容量%s\n", cap(j))
    fmt.Printf("j长度%s\n", len(j))
    x := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    fmt.Println(x)
    fmt.Printf("x容量%s\n", cap(x))
    fmt.Printf("x长度%s\n", len(x))
    x = append(x, 11)
    fmt.Println(x)
    fmt.Printf("x容量%s\n", cap(x))
    fmt.Printf("x长度%s\n", len(x))
    var y []int
    for u := 0; u < 10; u++ {
        //y = append(y, fmt.Sprintf("%v", u))
        y = append(y, u)
    }
    fmt.Println(y)
    fmt.Printf("y容量%s\n", cap(y))
    fmt.Printf("y长度%s\n", len(y))
    y = append(y, 5)
    fmt.Println(y)
    var z = make([]int, len(y))
    copy(z, y)
    fmt.Println(z)
    y[0] = 9
    fmt.Println(y)
    fmt.Println(z)

结果

qde

abqdefgh

j容量%!s(int=10)

j长度%!s(int=8)

[0 1 2 3 4 5 6 7 8 9]

x容量%!s(int=10)

x长度%!s(int=10)

[0 1 2 3 4 5 6 7 8 9 11]

x容量%!s(int=20)

x长度%!s(int=11)

[0 1 2 3 4 5 6 7 8 9]

y容量%!s(int=16)

y长度%!s(int=10)

[0 1 2 3 4 5 6 7 8 9 5]

[0 1 2 3 4 5 6 7 8 9 5]

[9 1 2 3 4 5 6 7 8 9 5]

[0 1 2 3 4 5 6 7 8 9 5]

后来我再给y加入个成员,他的容量还是16,为了弄清容量和长度的关系

我写个循环看看

for u := 0; u < 20; u++ {
        //y = append(y, fmt.Sprintf("%v", u))
        y = append(y, u)
        fmt.Printf("y长度%s\n", len(y))
        fmt.Printf("y容量%s\n", cap(y))
    }

结果是

y长度%!s(int=1)

y容量%!s(int=2)

y长度%!s(int=2)

y容量%!s(int=2)

y长度%!s(int=3)

y容量%!s(int=4)

y长度%!s(int=4)

y容量%!s(int=4)

y长度%!s(int=5)

y容量%!s(int=8)

y长度%!s(int=6)

y容量%!s(int=8)

y长度%!s(int=7)

y容量%!s(int=8)

y长度%!s(int=8)

y容量%!s(int=8)

y长度%!s(int=9)

y容量%!s(int=16)

y长度%!s(int=10)

y容量%!s(int=16)

y长度%!s(int=11)

y容量%!s(int=16)

y长度%!s(int=12)

y容量%!s(int=16)

y长度%!s(int=13)

y容量%!s(int=16)

y长度%!s(int=14)

y容量%!s(int=16)

y长度%!s(int=15)

y容量%!s(int=16)

y长度%!s(int=16)

y容量%!s(int=16)

y长度%!s(int=17)

y容量%!s(int=32)

y长度%!s(int=18)

y容量%!s(int=32)

y长度%!s(int=19)

y容量%!s(int=32)

y长度%!s(int=20)

y容量%!s(int=32)

呵呵 ,这下明白了,添加成员时,容量是2的指数递增的,2,4,8,16,32。

而且是在长度要超过容量时,才增加容量。

我想在以后的开发中,切片我一定会比数组用的多,因为在原来的项目里,几乎所有数组都是无法提前知道它的长度的,都是会随时增加成员的。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。如有错误或未考虑完全的地方,望不吝赐教。

Golang 相关文章推荐
go语言map与string的相互转换的实现
Apr 07 Golang
Go语言-为什么返回值为接口类型,却返回结构体
Apr 24 Golang
golang中切片copy复制和等号复制的区别介绍
Apr 27 Golang
Golang 如何实现函数的任意类型传参
Apr 29 Golang
使用golang编写一个并发工作队列
May 08 Golang
Go语言实现Snowflake雪花算法
Jun 08 Golang
go web 预防跨站脚本的实现方式
Jun 11 Golang
浅谈Go语言多态的实现与interface使用
Jun 16 Golang
golang中字符串MD5生成方式总结
Jul 04 Golang
Go语言基础map用法及示例详解
Nov 17 Golang
Golang使用Panic与Recover进行错误捕获
Mar 22 Golang
Golang数据类型和相互转换
Apr 12 Golang
go语言中切片与内存复制 memcpy 的实现操作
Apr 27 #Golang
Go语言中的UTF-8实现
Apr 26 #Golang
golang中实现给gif、png、jpeg图片添加文字水印
Apr 26 #Golang
Go语言带缓冲的通道实现
Apr 26 #Golang
go语言求任意类型切片的长度操作
Apr 26 #Golang
golang如何去除多余空白字符(含制表符)
Apr 25 #Golang
用golang如何替换某个文件中的字符串
Apr 25 #Golang
You might like
Php-Redis安装测试笔记
2015/03/05 PHP
php实现猴子选大王问题算法实例
2015/04/20 PHP
超越Jquery_01_isPlainObject分析与重构
2010/10/20 Javascript
javascript设计模式 封装和信息隐藏(上)
2012/07/24 Javascript
JS获取并操作iframe中元素的方法
2013/03/21 Javascript
js数组操作学习总结
2013/11/04 Javascript
JavaScript中输出标签的方法
2014/08/27 Javascript
jQuery实现防止提交按钮被双击的方法
2015/03/24 Javascript
jQuery实现的图文高亮滚动切换特效实例
2015/08/10 Javascript
JS限定手机版中图片大小随分辨率自动调整的方法
2016/12/05 Javascript
vue router自动判断左右翻页转场动画效果
2017/10/10 Javascript
JS中用EL表达式获取上下文参数值的方法
2018/03/28 Javascript
详解Eslint 配置及规则说明
2018/09/10 Javascript
使用puppeteer爬取网站并抓出404无效链接
2018/12/20 Javascript
javascript使用链接跨域下载图片
2019/11/01 Javascript
Vue的props父传子的示例代码
2020/05/20 Javascript
Vue按时间段查询数据组件使用详解
2020/08/21 Javascript
Djang中静态文件配置方法
2015/07/30 Python
谈谈Python进行验证码识别的一些想法
2016/01/25 Python
基于python实现的百度音乐下载器python pyqt改进版(附代码)
2019/08/05 Python
Django获取应用下的所有models的例子
2019/08/30 Python
打包PyQt5应用时的注意事项
2020/02/14 Python
pytorch模型存储的2种实现方法
2020/02/14 Python
Jupyter notebook 远程配置及SSL加密教程
2020/04/14 Python
Python如何定义有默认参数的函数
2020/08/10 Python
Python HTMLTestRunner如何下载生成报告
2020/09/04 Python
触发器(trigger)的功能都有哪些?写出一个触发器的例子
2012/09/17 面试题
医学检验专业大学生求职信
2013/11/18 职场文书
家庭困难证明
2014/10/12 职场文书
六一儿童节开幕词
2015/01/29 职场文书
求职信:会计求职的写作技巧
2019/04/24 职场文书
励志正能量20句:送给所有为梦想拼搏的人
2019/11/11 职场文书
MYSQL如何查看进程和kill进程
2022/03/13 MySQL
springboot layui hutool Excel导入的实现
2022/03/31 Java/Android
Python如何快速找到多个字典中的公共键(key)
2022/04/29 Python
flex布局中使用flex-wrap实现换行的项目实践
2022/06/21 HTML / CSS