Sure, you can assign returned errors to the underscore black hole and move on. However, that is still consciously and deliberately "doing something" with it.
It is glaringly obvious in a code review that you have done this. Also, although I'm not personally familiar with any Go tools similar to PMD or Sonar in the Java world... it would be fairly easy to write a static analyzer that could scan code, recognize this pattern, and report on it (along with other code smells) in an automated manner.
Nevertheless, idiomatic Go functions return an error structure, and you must do something with that error structure. There is no ambiguity as to where the error structure came from.
Contrast that with Java's model, which is much more (pardon the expression) catch-all. There is endless debate on how wide or narrow to make your try-catch blocks, when to handle an exception locally vs. throwing it back to the caller, etc.
It is very common to deal with bugs that stem from silently "swallowing" exceptions at an inappropriately low level. It is just as common to see patterns where nearly all methods throw nearly everything without a catch at all... and there's a monster try-catch block at the top level catching the base "Exception" class.
Worst of all, there are entire classes of runtime exceptions which are NOT declared as throwable in the method's signature. The compiler has no means of insisting that you do anything about those, because the compiler doesn't know which ones are possible during a given method call. Go's error handling model is safer and better thought-out in that regard.
When you think about issues stemming from Java's handling of checked vs. unchecked exception types, it makes a lot more sense why Go went in the direction it did. Also, why Go application developers are discouraged from using "panic-recover"... and why Go library developers almost always recover from panics and create error structs for passing back upstream.
It is glaringly obvious in a code review that you have done this. Also, although I'm not personally familiar with any Go tools similar to PMD or Sonar in the Java world... it would be fairly easy to write a static analyzer that could scan code, recognize this pattern, and report on it (along with other code smells) in an automated manner.
Nevertheless, idiomatic Go functions return an error structure, and you must do something with that error structure. There is no ambiguity as to where the error structure came from.
Contrast that with Java's model, which is much more (pardon the expression) catch-all. There is endless debate on how wide or narrow to make your try-catch blocks, when to handle an exception locally vs. throwing it back to the caller, etc.
It is very common to deal with bugs that stem from silently "swallowing" exceptions at an inappropriately low level. It is just as common to see patterns where nearly all methods throw nearly everything without a catch at all... and there's a monster try-catch block at the top level catching the base "Exception" class.
Worst of all, there are entire classes of runtime exceptions which are NOT declared as throwable in the method's signature. The compiler has no means of insisting that you do anything about those, because the compiler doesn't know which ones are possible during a given method call. Go's error handling model is safer and better thought-out in that regard.
When you think about issues stemming from Java's handling of checked vs. unchecked exception types, it makes a lot more sense why Go went in the direction it did. Also, why Go application developers are discouraged from using "panic-recover"... and why Go library developers almost always recover from panics and create error structs for passing back upstream.