Golang 拷贝Array或Slice的操作

Golang中Array是值类型而slice是引用类型。因此两者之间的赋值或拷贝有些差异,本文带你了解各自的差异。

1. 拷贝array

前面提及数组是值类型,所以数组变量名不是指向第一个元素的指针。事实上它表示整个数组,下面两者情况将自动创建数组:

数组变量赋值给另一个数组变量

数组变量传递作为函数参数

请看示例:

package main
import "fmt"
func main() {
    sample1 := [2]string{"a", "b"}
    fmt.Printf("Sample1 Before: %v\n", sample1)
    sample2 := sample1
    sample2[0] = "c"
    fmt.Printf("Sample1 After assignment: %v\n", sample1)
    fmt.Printf("Sample2: %v\n", sample2)
    test(sample1)
    fmt.Printf("Sample1 After Test Function Call: %v\n", sample1)
}
func test(sample [2]string) {
    sample[0] = "d"
    fmt.Printf("Sample in Test function: %v\n", sample)
}

输出结果:

Sample1 Before: [a b]

Sample1 After assignment: [a b]

Sample2:

Sample in Test function: [d b]

Sample1 After Test Function Call: [a b]

我们稍作解释:

sample1 赋给 sample2 ,然后修改sample2中第一个元素。打印sample1验证是否有影响,当然没有改变。这是因为sample1 赋给 sample2,会创建sample1的拷贝给sample2,故修改sample2不影响sample1.

传递sample1给test函数,然后在函数体内修改其第一个元素。之后打印sample1验证是否有影响,当然也没有。原因是一样的,当sample1作为参数传递给test时,sample1的拷贝被创建并传入,因此修改不会影响原来sample1.

2. 拷贝slice

Golang内置包提供copy函数能够拷贝slice,函数前面如下,其返回拷贝元素个数:

func copy(dst, src []Type) int

使用copy函数需要考虑两种情况:

如果src长度大于dst,那么仅拷贝dst长度个元素

如果dst长度大于src,那么仅拷贝src长度个元素

总结为拷贝两者最小长度元素:min(src,dst)

需要注意的是,一旦拷贝完成,对目标的修改不会影响源,反之亦然。

我们也通过示例说明:

package main
import "fmt"
func main() {
    src := []int{1, 2, 3, 4, 5}
    dst := make([]int, 5)
    numberOfElementsCopied := copy(dst, src)
    fmt.Printf("Number Of Elements Copied: %d\n", numberOfElementsCopied)
    fmt.Printf("dst: %v\n", dst)
    fmt.Printf("src: %v\n", src)
    //After changing numbers2
    dst[0] = 10
    fmt.Println("\nAfter changing dst")
    fmt.Printf("dst: %v\n", dst)
    fmt.Printf("src: %v\n", src)
}

输出如下:

Number Of Elements Copied: 5

dst: [1 2 3 4 5]

src: [1 2 3 4 5]

After changing dst

dst: [10 2 3 4 5]

src: [1 2 3 4 5]

3. 总结

本文介绍了Go Array和Slice直接拷贝。Array是值类型直接赋值即拷贝,Slice是引用类型,直接赋值是指针会影响源Slice,但可以通过内置copy函数实现赋值功能。

补充:golang字节数组拷贝BlockCopy函数实现

在C#中,Buffer.BlockCopy(Array, Int32, Array, Int32, Int32) 函数使用比较广泛,其含义:

将指定数目的字节从起始于特定偏移量的源数组复制到起始于特定偏移量的目标数组。

参数 src Array 源缓冲区。 srcOffset Int32 src 中的字节偏移量,从零开始。 dst Array 目标缓冲区。 dstOffset Int32 dst 中的字节偏移量,从零开始。 count Int32 要复制的字节数。

go语言中实现如下:

func blockCopy(src []byte, srcOffset int, dst []byte, dstOffset, count int) (bool, error) {
    srcLen := len(src)
    if srcOffset > srcLen || count > srcLen || srcOffset+count > srcLen {
        return false, errors.New("源缓冲区 索引超出范围")
    }
    dstLen := len(dst)
    if dstOffset > dstLen || count > dstLen || dstOffset+count > dstLen {
        return false, errors.New("目标缓冲区 索引超出范围")
    }
    index := 0
    for i := srcOffset; i < srcOffset+count; i++ {
        dst[dstOffset+index] = src[srcOffset+index]
        index++
    }
    return true, nil
}

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

(0)

相关推荐

  • Golang常见错误之值拷贝和for循环中的单一变量详解

    前言 golang(中文名:go语言)是谷歌2009发布的第二款开源编程语言.Go语言专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全.支持并行进程..如果你想知道得更多,请移步至官网golang官网 在 Go 中函数的调用是值拷贝 copy value,而且在 for 循环中 v 的变量始终是一个变量.如果 v 是 pointer,print 这个 method 接收的是指针的拷贝,for 循环体中每次迭代 v 的 pointer va

  • 利用Golang实现TCP连接的双向拷贝详解

    前言 本文主要给大家介绍了关于Golang实现TCP连接的双向拷贝的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 最简单的实现 每次来一个Server的连接,就新开一个Client的连接.用一个goroutine从server拷贝到client,再用另外一个goroutine从client拷贝到server.任何一方断开连接,双向都断开连接. func main() { runtime.GOMAXPROCS(1) listener, err := net.Liste

  • Golang中禁止拷贝的实现代码

    前言 Go中没有原生的禁止拷贝的方式,所以如果有的结构体,你希望使用者无法拷贝,只能指针传递保证全局唯一的话,可以这么干,定义 一个结构体叫 noCopy,要实现 sync.Locker 这个接口 方法如下: // noCopy may be embedded into structs which must not be copied // after the first use. // // See https://golang.org/issues/8005#issuecomment-190

  • Golang 拷贝Array或Slice的操作

    Golang中Array是值类型而slice是引用类型.因此两者之间的赋值或拷贝有些差异,本文带你了解各自的差异. 1. 拷贝array 前面提及数组是值类型,所以数组变量名不是指向第一个元素的指针.事实上它表示整个数组,下面两者情况将自动创建数组: 数组变量赋值给另一个数组变量 数组变量传递作为函数参数 请看示例: package main import "fmt" func main() { sample1 := [2]string{"a", "b&q

  • 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切片操作之切片的追加、删除、插入等

    本文介绍了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中range在slice和map遍历中的注意事项

    golang中range在slice和map遍历中的注意事项 package main import ( "fmt" ) func main() { slice := []int{0, 1, 2, 3} myMap := make(map[int]*int) for _,v :=range slice{ if v==1 { v=100 } } for k,v :=range slice{ fmt.Println("k:",k,"v:",v) }

  • Array.prototype.slice.apply的使用方法

    复制代码 代码如下: function test(){ //将参数转为一个数组 var args = Array.prototype.slice.apply(arguments); alert(args); } arguments在JavaScript语法中是函数特有的一个对象属性(Arguments对象),用来引用调用该函数时传递的实际参数.这个对象很象数组,拥有length属性且使用下标的形式来获取其元素,但它又并非真正的Array对象.更多关于Arguments对象的资料请参阅<JavaS

  • golang针对map的判断,删除操作示例

    本文实例讲述了golang针对map的判断,删除操作.分享给大家供大家参考,具体如下: map是一种key-value的关系,一般都会使用make来初始化内存,有助于减少后续新增操作的内存分配次数.假如一开始定义了话,但没有用make来初始化,会报错的. 复制代码 代码如下: package main import ( "fmt" ) func main(){ var test =  map[string]string{"姓名":"李四",&qu

  • Array.prototype.slice 使用扩展

    除了正常用法,slice 经常用来将 array-like 对象转换为 true array. 名词解释:array-like object – 拥有 length 属性的对象,比如 { 0: 'foo', length: 1 }, 甚至 { length: 'bar' }. 最常见的 array-like 对象是 arguments 和 NodeList. 查看 V8 引擎 array.js 的源码,可以将 slice 的内部实现简化为: 复制代码 代码如下: function slice(s

  • 浅谈javascript的Array.prototype.slice.call

    写字前面 在js中我们经常会看到Array.prototype.slice.call(arguments,0)的写法,当然,这个方法的作用也许大家都明白,那就是把类数组对象转换成一个真正的数组.关于这个方法,我说说自己的理解. 这里涉及到slice()方法和call()方法,所以先简单说说这两个方法. slice()方法 数组和字符串都有这个slice方法,这个方法的作用是截取一段数据.它接收两个参数,第一个参数是要截取的位置索引,第二参数可选,表示要截取到的结束位置,但是不包括结束位置.在数组

  • js利用prototype调用Array的slice方法示例

    复制代码 代码如下: <script type="text/javascript"> function fn(name){ if(typeof name === "string"){ var args = Array.prototype.slice.call( arguments, 1 ); for(var i=0;i<args.length;i++){ alert(args[i]);//结果: 111 222 } } } function cal

  • javascript Array.prototype.slice使用说明

    除了正常用法,slice 经常用来将 array-like 对象转换为 true array. 名词解释:array-like object – 拥有 length 属性的对象,比如 { 0: 'foo', length: 1 }, 甚至 { length: 'bar' }. 最常见的 array-like 对象是 arguments 和 NodeList. 查看 V8 引擎 array.js 的源码,可以将 slice 的内部实现简化为: 复制代码 代码如下: function slice(s

随机推荐