Most languages would encode such behavior in a trait or a protocol instead of a zero-length struct field. It's type information and ought to be encoded in the type. From that perspective, I think it is a hack.
Go's entire schtick is being simple, eschewing language complexity in favour of letting the programmer handle it themself. Like C, but with pointer safety and garbage collection.
We learned from C++ and Rust that languages can be so smart that people can't effectively use them. Go is the opposite. It's so dumb that anyone can use it, but it doesn't have some native language features you might want.
This feels like a style complaint and not one about substance. An inaccessible (because it's named _) zero-length struct field is just another kind of metadata. It also doesn't require you to pollute the method set, which would be a bigger issue.
The real hack to me is that anything which simply has Lock() and Unlock() methods is considered uncopyable.