- Yes, this is the way to do error handling in Go. By design, you can't let exceptions propagate to the callers "silently", you have to consider what makes sense at each step. I found that on large-scale projects, it makes it significantly easier to predict and test the error handling behavior of your code. It also forces you to put the error handling first, which (imho) results in more readable, less nested code.
- Truly global variables don't exist in Go — if a package
foo
exports a variableBar
, other packages will have to callfoo.Bar
to access it. That being said, it pretty much never makes sense to do that.
In the example you gave, cmd.go and project.go are in the same package, and all package-level variables are shared, so identifiers conflict. If you want this variable to be shared, it's more readable to put all functions that use it in the same file. - When you want to mock some of your functions, it's the sign that there should probably be an associated interface. You can then "mock" an interface easily, by re-implementing your interface in your tests and making it do whatever you want. I find this more readable and idiomatic than using complex frameworks.
Note on the last question: if your interface has many functions:
type Fooer interface {
Foo1(string) (string, error)
Foo2(int) (string, int)
...
// Foo42() []byte
}
and you only want to test Foo1
, you can use the following syntax
type fakeFooer struct {
Fooer
ret string
}
func (fi fakeFooer) Foo1(_ string) (string, error) {
return fi.ret, nil
}
and not implement any other functions. fakeFooer{"bar"}
will "implement" Fooer
, calling Foo1
will do what you expect, and trying to call Foo2
on it will panic (nil pointer dereference).
Ted
- 701
- 3
- 12
default