Struct assignment in Go copies the entire struct value in one assignment. That is a full copy of the struct’s own storage, but any field that contains a slice, map, or pointer still refers to the same underlying object as the source—what people often call a shallow copy of the aggregate. To test equality after copying, see compare structs, slices, and maps in Go. Primitives and fixed-size arrays inside the struct are independent after assignment. For pointers to structs, a new pointer can still refer to the same struct value, so mutations through the pointer affect every alias.
Tested with Go 1.24 on Linux.
Primitives and strings
package main
import "fmt"
func main() {
a := 64
b := 12.5
s := "Test string"
a2, b2, s2 := a, b, s
a2, b2, s2 = 105, 63, "Copy string"
fmt.Println(a, b, s)
fmt.Println(a2, b2, s2)
}You should see the originals unchanged on the first line and the updated copies on the second.
Slices and maps (shared backing)
package main
import "fmt"
func main() {
testSlice := []int{1, 3, 4, 5, 6, 7, 1}
testMap := map[string]int{"Red": 102, "Black": 253}
copySlice := testSlice
copyMap := testMap
copySlice[0] = 10000000
copyMap["Green"] = 1588963
fmt.Println(testSlice[0], copySlice[0])
fmt.Println(testMap["Green"], copyMap["Green"])
}You should see matching slice heads and the new map key visible on both variables.
Structs with only primitive fields
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
p1 := Person{"Anna", 23}
p2 := p1
p2.Name = "Bob"
fmt.Println(p1.Name, p2.Name)
}You should see Anna and Bob.
Struct with a slice field (shared unless you copy)
package main
import "fmt"
type Person struct {
Name string
Age int
Friends []string
}
func main() {
p1 := Person{"Anna", 23, []string{"Bob", "Teddy", "Wilson"}}
p2 := p1
p2.Friends = append(p2.Friends, "Kelly")
fmt.Println(len(p1.Friends), p1.Friends[len(p1.Friends)-1])
}You should see 4 and Kelly on the last element because p1 and p2 share the same backing array until you replace the slice field with an independent copy.
Taking the address with p3 := &p1 does not duplicate the struct; writes through p3 still hit the same value (including the same slice header) as p1.
Summary
Golang copy struct behavior is “copy the whole value once.” That duplicates primitive fields and array storage inside the struct, but slice, map, and pointer fields still alias unless you assign freshly allocated values (for example Friends: append([]string(nil), p1.Friends...)). Choose explicit duplication or serialization when you need full isolation.
References
Frequently Asked Questions
Does person2 := person1 deep copy a struct in Go?
It copies the struct value in one step. If a field holds a slice, map, or pointer, both variables see the same underlying data unless you rebuild those fields.
How is copying a struct different from copying a map or slice variable?
Assigning a map or slice variable copies the header that points to shared storage; struct assignment copies the whole struct bit pattern in one go, which still embeds those headers for reference-type fields.
How do I deep copy a struct with a slice field?
Copy the struct, then replace the slice field with a new slice and use copy() from the original, or use encoding/json, gob, or a small hand-written Clone method.
What does person2 := &person1 do?
person2 points at person1; changes through the pointer modify the same struct value including shared slice backing arrays.
Where can I read about pointers in Go?
See the pointers tutorial for addresses, dereferencing, and when to pass pointers to functions.

