Maybe it’s a good thing it’s not widely known, generics are trivial to discover.
func processItem(item *string) {
if item == nil {
fmt.Println("nil item")
return
}
fmt.Println(*item)
}
stuffToProcess := []string{"one", "two"}
wg := sync.WaitGroup{}
for _, item := range stuffToProcess {
wg.Add(1)
go func(s *string) {
time.Sleep(1 * time.Millisecond)
processItem(s)
wg.Done()
}(&item)
}
wg.Wait()
// What do I print?
Playground here: https://play.golang.org/p/mouvT1BkpNJI assume GGP's contrived example is to show the underlying mechanics of the issue.
[reuse.go:26] - G601 (CWE-118): Implicit memory aliasing in for loop. (Confidence: MEDIUM, Severity: MEDIUM)
25: wg.Done()
> 26: }(&item)
27: }
[1] https://github.com/securego/gosecIt's inability to deal with cyclic references, the lack of overloading, the lack of package-level visibility and the lack of static functions all contribute to a lot of ceremony.
You end up with functions like newUserWithPassword and NewRole (casing intentional), instead of User::new() and Role::new()
You could just have a NewUser that takes a NewUserOpts which exposes a fluent interface. But again, a lot of ceremony.
You can use a package per type, but still no overloading, and you'll need a 3rd package to bridge the two if the reference each other.
After 4 years of Go, this is usually a design thing. Once I figured out how to separate and isolate domains of interest better, I stopped running into these issues entirely. My code, in and outside of Go, is much better for it. I also learned that much of "thread-safe" programming is taught this way, which makes sense.
I've been getting into Go for the past couple of months, but I still struggle with this.