The remove logic is correct (your output confirms this too). The problem is the lack of synchronization between multiple goroutines (your question says nothing about this).
You said (in your comment) that you wanted this to get working with 1 goroutine first, and deal with synchronization later. But your code already uses multiple goroutines, so you can't have that luxury:
//Let a goroutine Handle the connection
go handleConnection(conn)
Multiple goroutines are reading and writing the Room.Visitors
slice, so you have no choice but to synchronize access to it.
An example would be to use sync.RWLock
:
utils.go
:
type Room struct {
mu sync.RWLock
Name string
Visitors []net.Conn
}
func (r *Room) Leave(c net.Conn) {
r.mu.Lock()
defer r.mu.Unlock()
for i, v := range r.Visitors {
//found the connection we want to remove
if c == v {
fmt.Printf("Before remove %v\n", r.Visitors)
r.Visitors = append(r.Visitors[:i], r.Visitors[i+1:]...)
fmt.Printf("After remove %v\n", r.Visitors)
return
}
}
}
Also whenever any other code touches Room.Visitors
, also lock the code (you may use RWMutex.RLock()
if you're just reading it).
Similarly you need to synchronize access to all variables that are read/changed by multiple goroutines.
Also consider zeroing the element that is freed after the removal, else the underlying array will still hold that value, preventing the garbage collector to properly free memory used by it. For more information about this, see Does go garbage collect parts of slices?