I have a struct "Guest" which contains metadata of a party guest (a unique ID, name, surname and a list of the unique IDs of the guests who are friends of this guest.
type Guest struct {
id int
name string
surname string
friends []int
}
I have the following code to remove an ID from the list of friends:
func (self Guest) removeFriend(id int) {
for i, other := range self.friends {
if other == id {
self.friends = append(self.friends[:i], self.friends[i+1:]...)
break
}
}
}
The problem is: The element I want to remove is overwritten by the shift of the elements, but the slice does not get shorter. Instead, the last element of the slice is multiplied.
To give an example: guest1.friends
is [1,2,3,4,5]
. After I call guest1.removeFriend(3)
, the result is [1,2,4,5,5]
instead of the desired [1,2,4,5]
.
So, what am I doing wrong?
Any method that intends / does modify the receiver must use a pointer receiver.
Your
Guest.removeFriend()
method indeed tries to modify the receiver (of typeGuest
), namely itsfriends
field (which is of slice type), but since you only used a value receiver, you are only modifying thefriends
field of aGuest
copy. The originalGuest
value will have the unmodified slice value.So you must use a pointer receiver:
Testing it:
Output (try it on the Go Playground):
The explanation for what you see in your version that slices are small struct descriptors pointing to an array that actually holds the elements. In your example you modified the elements of the backing array, so the caller having the original slice will see those modifications, but the size of the original slice will not (cannot) change.
By using a pointer receiver, you will assign the new slice value (returned by
append()
) to thefriends
field of the originalGuest
, the slice value whose length will be smaller by 1 (due to the 1 removed element).Also note that in Go using receiver names like
self
andthis
is not idiomatic, instead you could useguest
or simplyg
.