When you receive a slice or map as an argument in Go, keep in mind that it's passed by reference. This means that if you store the reference, any modifications to the original slice or map outside your function will affect your stored data. To prevent this, create a copy before storing it.
Example: Avoiding Side Effects
Here's how you could implement this with a LoadBalancer struct that stores server IPs. By copying the slice, we avoid any unintended modifications.
type LoadBalancer struct {
servers []string
}
func (lb *LoadBalancer) SetServers(servers []string) {
lb.servers = make([]string, len(servers))
copy(lb.servers, servers)
}
func main() {
serverList := []string{"192.168.1.1", "192.168.1.2"}
lb := LoadBalancer{}
lb.SetServers(serverList)
// Modify serverList without affecting lb's servers
serverList[0] = "10.0.0.1"
fmt.Println(lb.servers) // Output: ["192.168.1.1", "192.168.1.2"]
}
In this example, SetServers
creates a copy of servers
before storing it in lb.servers
, ensuring that changes to serverList
outside the LoadBalancer
do not affect the stored IPs.
Maps Work the Same Way
The same applies to maps, as they're also reference types. To prevent external modifications, create a new map and copy values:
type LoadBalancer struct {
config map[string]string
}
func (lb *LoadBalancer) SetConfig(config map[string]string) {
lb.config = make(map[string]string, len(config))
for key, value := range config {
lb.config[key] = value
}
}
By copying the config
map, any changes to the original map won't affect the LoadBalancer
's stored configuration.
When storing slices or maps passed as arguments, copy them to maintain data integrity. This practice ensures your data remains stable, preventing unintended side effects from external modifications.