golang切片拷贝的实现

 更新时间:2024年10月15日 10:22:37   作者:快刀一哥  
在Golang中,切片的浅拷贝只复制指向对象的指针,而深拷贝则复制数据本身,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

golang切片有浅拷贝和深拷贝的区别

1、深拷贝(Deep Copy)

拷贝的是数据本身,创造一个样的新对象,新创建的对象与原对象不共享内存,新创建的对象在内存中开辟一个新的内存地址,新对象值修改时不会影响原对象值。既然内存地址不同,释放内存地址时,可分别释放。

值类型的数据,默认全部都是深复制,Array、Int、String、Struct、Float,Bool。

2、浅拷贝(Shallow Copy)

拷贝的是数据地址,只复制指向的对象的指针,此时新对象和老对象指向的内存地址是一样的,新对象值修改时老对象也会变化。释放内存地址时,同时释放内存地址。

引用类型的数据,默认全部都是浅复制,Slice,Map。

去若是浅拷贝,原始的切片变化后所有的切片都会变化,无论切片是否在一个函数,还是一个goroutine中,都会发生变化

如下代码为例子

package main

import "fmt"

func main() {
	
	// 创建一个切片
	originalSlice := []int{1, 2, 3, 4, 5}

	// 使用切片[:]操作符创建浅拷贝
	shallowCopy := originalSlice[:]
	shallowCopy2 := make([]int, len(shallowCopy))
	copy(shallowCopy2, originalSlice)

	// 修改原始切片的元素
	originalSlice[0] = 100

	// 输出原始切片和浅拷贝的切片
	fmt.Println("Original Slice:", originalSlice)
	fmt.Println("Shallow Copy:", shallowCopy)
	fmt.Println("Shallow Copy2:", shallowCopy2)
}

如下代码问题困扰了好久,才发现是切片赋值的问题

func (sf *ServerSession) running(ctx context.Context, subcom []uint8) {
	var err error
	var bytesRead int

	defer func() {
		sf.conn.Close()

	}()
	go sf.prehandler()

	raw := make([]byte, tcpAduMaxSize)

	for {
		select {
		case <-ctx.Done():
			err = errors.New("server active close")
			xlog.Errorln(err)
			return
		default:
		}

		err = sf.conn.SetReadDeadline(time.Now().Add(sf.readTimeout))
		if err != nil {
			xlog.Errorln("set read tcp data time deadline error:", err)
		}
		count, err := sf.conn.Read(raw)

		if err != nil {
			if err != io.EOF && err != io.ErrClosedPipe || strings.Contains(err.Error(), "use of closed network connection") {
				return
			}

			if e, ok := err.(net.Error); ok && !e.Temporary() {
				return
			}

			if bytesRead == 0 && err == io.EOF {
				err = fmt.Errorf("remote client closed, %v", err)
				xlog.Errorln(err)
				return
			}
			// cnt >0 do nothing
			// cnt == 0 && err != io.EOF continue do it next
		}
		adu := raw[:count]

		prodata := new(ProcessData)
		prodata.adu = make([]byte, len(adu))
		copy(prodata.adu, adu)
		prodata.count = count
		prodata.subcom = subcom
		Prodatach <- prodata

	}
}

func (sf *ServerSession) prehandler() {
	for {
		select {
		case prodata := <-Prodatach:
			go sf.prerunhandler(prodata)

		}
	}
}
func (sf *ServerSession) prerunhandler(prodata *ProcessData) {
	length := prodata.count
	adu := make([]byte, len(prodata.adu))
	copy(adu, prodata.adu)
	subcom := prodata.subcom
	xlog.Debug("run handler input1 out1 adu [% X] length is:%d\n", adu, length)
	//可能一次读出来多个数据包 增加处理方式 @20240704
	//直接在for循环中使用
	for length > 0 {
		headdata := adu[:gaHeaderSize]
		head1 := new(gadataHeader)
		buf1 := bytes.NewReader(headdata)
		err := binary.Read(buf1, binary.BigEndian, head1)
		if err != nil {
			xlog.Errorln("ga server decode errr:", err)
		}
		xlog.Debugln("pre process packect SN:", head1.SN)
		galength := int(head1.Datalength) + gaHeaderSize

		if galength <= len(adu) {
			adu1 := adu[:galength]
			xlog.Debug("run handler input out adu [% X ],galength is:%d subcom is %d length is:%d\n", adu1, galength, subcom, length)
			sf.runhandler(adu1, galength, subcom)
			adu = adu[galength:]
			length -= galength

		} else {
			xlog.Debug("data length is %d, adu length is:%d\n", head1.Datalength, len(adu))
			break
		}

	}
}
func (sf *ServerSession) runhandler(adu []byte, count int, subcom []uint8) {
	if count < gaHeaderSize {
		return
	}
	xlog.Debug("run handler input adu [% X ],count is:%d subcom is %d", adu, count, subcom)
	// xlog.Debug("recive data [% x] count is % d \n", adu, count)
	head1 := new(gadataHeader)
	data := adu[:gaHeaderSize]
	buf1 := bytes.NewReader(data)
	err := binary.Read(buf1, binary.BigEndian, head1)
	if err != nil {
		xlog.Errorln("ga server decode errr:", err)
	}
	xlog.Debugln("gaserver head sn:", head1.SN)

	if !Find(subcom, head1.Subcomid) {
		xlog.Debug("subcom: %d is not in array %d \n", head1.Subcomid, subcom)
		return
	}
	// check head ProtocolIdentifier
	// if binary.BigEndian.Uint16(adu[2:]) != tcpProtocolIdentifier {
	// 	rdCnt, length = 0, tcpHeaderMbapSize
	// 	continue
	// }
	length := int(head1.Datalength) + gaHeaderSize
	if count == length {
		xlog.Debug("start decode packet SN is:%d subcom is %d data length is:%d\n", head1.SN, head1.Subcomid, head1.Datalength)
		if err = sf.frameHandler(adu); err != nil {
			xlog.Errorln("gaserver decode error:", err)
			return
		}
	} else {
		xlog.Debug("head data length: %d is not right %d \n", head1.Datalength, count)
		///此处经常出现问题
		xlog.Debug("adu data is [% X] \n", adu)
	}
}
func Find(subcoms []uint8, subcom uint8) bool {
	for i := 0; i < len(subcoms); i++ {
		if subcoms[i] == subcom {
			return true
		}
	}
	return false
}

出现非常奇怪的问题切片内容经常莫名奇妙的改变,最后发现是切片赋值的问题

1449[xx] 2024-07-05 16:28:03.428417 run handler input1 out1 adu [00 C4 11 0A 01 A3 00 0A 00 A1 42 79 08 20 1F 75 A0 00
 00 C5 11 06 01 A3 00 18 00 79 00 00 00 00 00 C0 C2 92 00 00 00 8D 42 95 85 C5 00 97 42 92 3D 71 ] length is:50
1450 [xx] 2024-07-05 16:28:03.428496 pre process packect SN: 196

1452[xx] 2024-07-05 16:28:03.448860 run handler input out adu [00 C6 11 40 01 A3 00 09 00 B6 00 05 53 65 76 65 6E 00 ],galength is:18 subcom is [17 41] length is:50
1453[xx] 2024-07-05 16:28:03.448985 run handler input adu [00 C6 11 40 01 A3 00 09 00 B6 00 05 53 65 76 65 6E 00 ],count is:18 subcom is [17 41]1454 [xx] 2024-07-05 16:28:03.449011 gaserver head sn: 198

到此这篇关于golang切片拷贝的实现的文章就介绍到这了,更多相关golang切片拷贝内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go 互斥锁和读写互斥锁的实现

    Go 互斥锁和读写互斥锁的实现

    本文主要介绍了Go 互斥锁和读写互斥锁的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • 如何使用Golang发送Get和Post请求

    如何使用Golang发送Get和Post请求

    这篇文章主要给大家介绍了关于如何使用Golang发送Get和Post请求的相关资料,Go语言(Golang)的标准库提供了处理HTTP请求的功能,这使得将Go用于web应用程序变得非常容易,需要的朋友可以参考下
    2023-06-06
  • golang实现分页算法实例代码

    golang实现分页算法实例代码

    这篇文章主要给大家介绍了关于golang实现分页算法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-09-09
  • go Http Post 发送文件流案例

    go Http Post 发送文件流案例

    这篇文章主要介绍了go Http Post 发送文件流案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • Go语言如何生成PDF文件实例探究

    Go语言如何生成PDF文件实例探究

    这篇文章主要为大家介绍了Go语言生成PDF文件的实例探究,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • 重学Go语言之如何开发RPC应用

    重学Go语言之如何开发RPC应用

    这篇文章主要为大家详细介绍了在Go语言中如何构建RPC应用,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-09-09
  • 浅谈golang中的&^位清空操作

    浅谈golang中的&^位清空操作

    这篇文章主要介绍了浅谈golang中的&^位清空操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • go mod tidy报错:zip: not a valid zip file解决办法

    go mod tidy报错:zip: not a valid zip file解决办法

    这篇文章主要给大家介绍了关于go mod tidy报错:zip: not a valid zip file的解决办法,go mod是进行代码管理,这错误是因为本地分支和远程分支冲突,本文通过代码介绍的非常详细,需要的朋友可以参考下
    2024-01-01
  • go语言接口之接口值举例详解

    go语言接口之接口值举例详解

    接口是一种抽象类型,是对其他类型行为的概括与抽象,从语法角度来看,接口是一组方法定义的集合,下面这篇文章主要给大家介绍了关于go语言接口之接口值的相关资料,文章通过代码介绍的非常详细,需要的朋友可以参考下
    2024-06-06
  • golang使用go mod导入本地包和第三方包的方式

    golang使用go mod导入本地包和第三方包的方式

    这篇文章主要介绍了golang使用go mod导入本地包和第三方包的方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01

最新评论