If you don't need to manipulate pointers then nil really just represents a degenerate or optional value. For optional values these can be encoded any number of ways depending on the type system. One common pattern is an optional type. Another is to annotate the type to indicate that it might be null.
The idea is that if a programmer doesn't check that an nullable or optional type is missing then the program should fail at compile time instead of crashing at runtime. Golang chose to crash programs at runtime.
So for whatever reason, Go has decided that null pointer dereferences are not a big deal. But God help you if you try to comment out a variable use without assigning it to "_". Then the program fails to compile.
I think that's a good explanation of why people are so frustrated with this. There are lots of features like go fmt, go vet, the compiler checking that you use all variables and all imports that can feel a bit restrictive. But for something like null pointers, there is nothing. It's incoherent.
* separate pointer types (e.g. C++ pointers v references)
* a built-in sigil / wrapper / suffix e.g. C#'s Nullable / `?` types
* a bog-standard userland sum type e.g. Maybe/Option/Optional
In modern more procedural languages the third option often will have language-level (non-userland) facilities tackled on for better usability but that's not a requirement.
For cases (2) and (3) it can (depending on language and implementation) also provides a mechanism for making other value types optional without necessarily having to heap-allocate them.