Golang slices have the difference between shallow copy and deep copy
1. Deep Copy
What is copied is the data itself, creating a new object. The newly created object does not share memory with the original object. The newly created object opens a new memory address in the memory. The new object value will not affect the original object value when it is modified. Since the memory addresses are different, they can be released separately when the memory addresses are released.
All data of value type are copied by default, such as Array, Int, String, Struct, Float, and Bool.
2. Shallow Copy
The copy is the data address, and only the pointer to the object is copied. At this time, the memory address pointed to by the new object and the old object are the same. The old object will also change when the new object value is modified. When the memory address is released, the memory address is released at the same time.
Reference types of data, all by default are shallow copy, Slice, and Map.
If it is a shallow copy, all slices will change after the original slice changes, regardless of whether the slice is in a function or a goroutine.
The following code is an example
package main import "fmt" func main() { // Create a slice originalSlice := []int{1, 2, 3, 4, 5} // Create shallow copy using the slice[:] operator shallowCopy := originalSlice[:] shallowCopy2 := make([]int, len(shallowCopy)) copy(shallowCopy2, originalSlice) // Modify the element of the original slice originalSlice[0] = 100 // Output original slices and shallow copies of slices ("Original Slice:", originalSlice) ("Shallow Copy:", shallowCopy) ("Shallow Copy2:", shallowCopy2) }
The following code problem has been plagued by a long time before I found out that it is a problem with slice assignment
func (sf *ServerSession) running(ctx , subcom []uint8) { var err error var bytesRead int defer func() { () }() go () raw := make([]byte, tcpAduMaxSize) for { select { case <-(): err = ("server active close") (err) return default: } err = (().Add()) if err != nil { ("set read tcp data time deadline error:", err) } count, err := (raw) if err != nil { if err != && err != || ((), "use of closed network connection") { return } if e, ok := err.(); ok && !() { return } if bytesRead == 0 && err == { err = ("remote client closed, %v", err) (err) return } // cnt >0 do nothing // cnt == 0 && err != continue do it next } adu := raw[:count] prodata := new(ProcessData) = make([]byte, len(adu)) copy(, adu) = count = subcom Prodatach <- prodata } } func (sf *ServerSession) prehandler() { for { select { case prodata := <-Prodatach: go (prodata) } } } func (sf *ServerSession) prerunhandler(prodata *ProcessData) { length := adu := make([]byte, len()) copy(adu, ) subcom := ("run handler input1 out1 adu [% X] length is:%d\n", adu, length) //Maybe multiple data packets can be read out at once. Add processing method @20240704 //Use directly in the for loop for length > 0 { headdata := adu[:gaHeaderSize] head1 := new(gadataHeader) buf1 := (headdata) err := (buf1, , head1) if err != nil { ("ga server decode errr:", err) } ("pre process packect SN:", ) galength := int() + gaHeaderSize if galength <= len(adu) { adu1 := adu[:galength] ("run handler input out adu [% X ],galength is:%d subcom is %d length is:%d\n", adu1, galength, subcom, length) (adu1, galength, subcom) adu = adu[galength:] length -= galength } else { ("data length is %d, adu length is:%d\n", , len(adu)) break } } } func (sf *ServerSession) runhandler(adu []byte, count int, subcom []uint8) { if count < gaHeaderSize { return } ("run handler input adu [% X ],count is:%d subcom is %d", adu, count, subcom) // ("recive data [% x] count is % d \n", adu, count) head1 := new(gadataHeader) data := adu[:gaHeaderSize] buf1 := (data) err := (buf1, , head1) if err != nil { ("ga server decode errr:", err) } ("gaserver head sn:", ) if !Find(subcom, ) { ("subcom: %d is not in array %d \n", , subcom) return } // check head ProtocolIdentifier // if .Uint16(adu[2:]) != tcpProtocolIdentifier { // rdCnt, length = 0, tcpHeaderMbapSize // continue // } length := int() + gaHeaderSize if count == length { ("start decode packet SN is:%d subcom is %d data length is:%d\n", , , ) if err = (adu); err != nil { ("gaserver decode error:", err) return } } else { ("head data length: %d is not right %d \n", , count) ///There are frequent problems here ("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 }
Very strange problems occur. Slice content often changes inexplicably, and finally it is found that it is a problem with slice assignment.
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: 1961452[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
This is the end of this article about the implementation of golang slice copy. For more related golang slice copy content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!