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.

