我应该避免在golang中打包单例吗?

at the moment I have a package store with following content:

package store

var (
    db *Database
)

func Open(url string) error {
    // open db connection
}

func FindAll(model interface{}) error {
    // return all entries
}

func Close() {
    // close db connection
}

This allows me to use store.FindAll from other packages after I have done store.Open in main.go.

However as I saw so far most packages prefer to provide a struct you need to initialize yourself. There are only few cases where this global approach is used.

What are downsides of this approach and should I avoid it?

The standard http package has a ServerMux for generic usecases and but also has one default instance of ServerMux called DefaultServerMux (http://golang.org/pkg/net/http/#pkg-variables) for convenience. So that when you call http.HandleFunc it creates the handler on the default mux. You can find the same approach used in log and many other packages. This is essentially your "singleton" approach.

However, I don't think it's a good idea to follow that pattern in your use case, since the users need to call Open regardless of the default database. And, because of that, using a default instance would not really help and instead would actually make it less convenient:

d := store.Open(...)
defer d.Close()
d.FindAll(...)

is much easier to both write and read than:

store.Open(...)
defer store.Close()
store.FindAll(...)

And, also there are semantic problems: what should happen if someone calls Open twice:

store.Open(...)
defer store.Close()
...
store.Open(...)
store.FindAll(...) // Which db is this referring to?
  1. You can't instantiate connections to 2 storages at once.
  2. You can't easily mock out storage in unit tests of dependent code using convenient tools like gomock.