The major differences in my head are:
- Garbage Collection
- Interfaces
There are some other more minor things like defer and the built-in generic types but many C programmers already had macros to implement similar things.
So sure, Go doesn't solve all of the problem spaces that C does. But if you are in a problem space where you don't need see (or another low-level systems language) Go may be a middle ground to move C programmers to.
So currently the issue is you can't write baremetal stuff in Go, for example the linux kernel or Arduinos. You can't get rid of GC if you have realtime requirements.
GO is 'close enough' to C in many areas like writing server-side code and CLI tools - it's GC pauses are short, even though C could produce an executables in a few KB, rather than an MB, that has no practical relevance in those areas.
If I needed a C alternative, rust gives me all (most of) the power of C, plus safety, without all the drawbacks of a heavy runtime.
If I am okay with paying the garbage collection tax, etc, then I would use scala or kotlin. If I'm using a higher level language, then I expect higher level features like exceptions, generics, reflection, etc.
I'm sure go is a great language with it's own usecases, but it's not a C replacement.
Most of the C lovers that I have spoken with find that Rust is far too complicated with templates and lifetimes. Similar arguments can be provided for Scala and Kotlin with their more functional syntax.
The thing that C/Go authors brought in straight from the seventies: utter garbage naming of identifiers.
But then again, the name of the language itself should be warning enough.
Compared to the alternative (straight assembler) at the time as a systems programming language, C is a massive step up.
Also, the UNIX way was independent processes, so the APIs did not need to be thread safe, as there was no threading in the target architectures.
Now given the massive amount of existing C out there from the time of such architectures, you either have to move the API and language on to make it incompatible with existing code, or support the old baggage. The language has kept compatibility, and in this case, the github peeps have deprecated APIs using macros, so it's a reasonable approach.
An alternative approach would be to move the language on, but by it's nature it won't be compatible with C, so you give it a new name. You call it things like go, or rust, or swift. These are all C with the dangerous bits removed. It'll be interesting in 40 years time to see if people are having the same conversation about these languages - 'OMG, how did people write stuff in rust? It can't cope with [insert feature of distributed quantum computing]. It's really scary'