Using defer with pointers - go

Let us say that I have the following code:
func getConnection(fileName string) *os.File {
file, err := os.Open(fileName)
//Check for error
return file
}
I use this function to open a file and the function is called from another function that does some other activity.
My question is, now that I have opened the file, how do I close it. If I were to add defer file.Close() inside getConnection(), wouldn't it close the file before returning? Does it make sense to use defer inside the calling function?

If the purpose of your function is to return a file, why would you want to close it in the function that returns it?
In this case it is the responsibility of the caller to properly close the file, preferably with defer:
func usingGetConnection() {
f := getConnection("file.txt")
defer f.Close()
// Use f here
}
Although your getConnection() function swallows errors, you should use multi-return value to indicate problems like this:
func getConnection(fileName string) (*os.File, error) {
file, err := os.Open(fileName)
//Check for error
if err != nil {
return nil, err
}
return file, nil
}
And using it:
func usingGetConnection() {
f, err := getConnection("file.txt")
if err != nil {
panic(err) // Handle err somehow
}
defer f.Close()
// Use f here
}

Related

go - Cleanup resources only when the function is about to return an error

Suppose I have a function that starts by creating a directory, and then doing some more stuff, like this:
{
err := os.Mkdir(path, os.ModePerm)
...
err = doSomething()
if err != nil {
return nil, err
}
err = doSomethingElse()
if err != nil {
return nil, err
}
return path, nil
}
Now, I want the function to delete the directory it created in all of those cases where an error occured. What is the cleanest way to do this?
One way would be to call os.RemoveAll in every if branch, but that's not a very nice solution. Another way would be to use a defer statement, but that would also get executed in the case where there was no error.
Yes, a deferred function will always be executed, but whether it deletes the directory depends entirely on you.
Use a deferred function, and check the error. If there was no error, do not delete the directory. For this to work, use named result parameters, e.g.:
func foo() (result resultType, err error) {
path := "some folder"
defer func() {
if err != nil { // This is the result err
if err2 := os.RemoveAll(path); err2 != nil {
// handle err2
}
}
}()
err := os.Mkdir(path, os.ModePerm)
...
}
Note that if there is an explicit return stament like:
return path, errors.New("bar")
The above return statement first assigns the values to result and err, so in deferred functions you can get / see those values.
See related: How to return a value in a Go function that panics?

How to defer resource cleanup when that resource outlives the scope of the surrounding function?

Let's take the example of this piece of code that makes the logger write to a local file instead of the standard output:
f, err := os.OpenFile("filename", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
log.Fatal(err)
}
defer f.Close()
log.SetOutput(f)
The author is putting this code straight into the main() function, which makes it work as intended. But if I wanted to put this code into a a dedicated function which main() may then call, then it would no longer work, because the f.Close() would be called before the logger ever gets used.
E.g. (if the code above is now in a function called logToFile()):
main() {
logToFile()
log.Print("I'm going to end up in stdout\n")
}
Can this be moved into its own function, and still have it work as intended?
I've had the same situation with opening/closing of a database connection. And it seems like the only way is to do both of these things inside the main(), but I think the code would look cleaner and more SoC if we could divide it into functions. Is this a no-no in Go?
You looking for something like this?
type closerFunc func() error
func logToFile(path string) closerFunc {
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
log.Fatal(err)
}
log.SetOutput(f)
return func() error {
return f.Close()
}
}
To use:
func main() {
closerFn := logToFile("filename")
defer closerFn()
log.Print("logs to file\n")
}
One option is to use continuation-passing style, passing the code to be executed within the defer block as an explicit argument:
func withLogToFile(filename string, body func()) {
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
log.Fatal(err)
}
prevOut := log.Writer()
log.SetOutput(f)
defer func() {
log.SetOutput(prevOut)
if err := f.Close(); err != nil {
log.Fatal(err)
}
}()
body()
}
Then the call site becomes:
func main() {
withLogToFile(filename, func() {
log.Print("I'm going to end up in ", filename)
})
}
(https://play.golang.org/p/ebCvtzufU5U)

gometalinter / errcheck returns a warning on deferring a func which returns a variable

gometalinter and errcheck return me a warning about deferring a function which returns a variable.
Example in a web request:
defer r.Body.Close()
In this case, Close returns an error variable and it's not checked.
Is the best method / idiomatic to defer it inside another function?
defer func() {
err := r.Body.Close()
if err != nil {
// fmt, panic or whatever
}
}()
If a deferred function has any return values, they are discarded when the function completes (for more details check Spec: Defer statements).
So the only way to check the return value is to store it, and it is only possible if not the function itself is deferred, but another function that calls it.
One way to do it is using an anonymous function as you did, which may be slightly simplified:
defer func() {
if err := r.Body.Close(); err != nil {
fmt.Println("Error when closing:", err)
}
}()
Or you may create a helper function for it:
func Check(f func() error) {
if err := f(); err != nil {
fmt.Println("Received error:", err)
}
}
And using it:
defer Check(r.Body.Close)
The helper function of course can be used multiple times, e.g.:
defer Check(r.Body.Close)
defer Check(SomeOtherFunc)
For which you may also create a modified helper function, which may accept multiple functions:
func Checks(fs ...func() error) {
for i := len(fs) - 1; i >= 0; i-- {
if err := fs[i](); err != nil {
fmt.Println("Received error:", err)
}
}
}
And using it:
defer Checks(r.Body.Close, SomeOtherFunc)
Note that I intentionally used a downward loop in Checks() to mimic the first-in-last-out nature of the execution of deferred functions, because the last defer will be executed first, and so using a downward loop the last function value passed to Checks() will be executed first.

Golang most efficient way to invoke method`s together

im looking for the most efficient way to invoke couple of method
together.
Basically what im trying to to is invoke those method together and if something went wrong return error else return the struct Type.
This code is working but i can't get the struct type or error and im not sure if its the correct way.
go func()(struct,err) {
struct,err= sm.MethodA()//return struct type or error
err = sm.MethodB()//return error or nill
return struct,err
}()
In Go, it's idiomatic to return the two values and check for nil against the error
For example:
func myFunc(sm SomeStruct) (MyStruct, error) {
s, err := sm.MethodA()
if err != nil {
return nil, err
}
if err := sm.MethodB(); err != nil {
return nil, err
}
return s, nil
}
One thing to note, is that you're running your function in a goroutine. Any return value inside that goroutine won't be returned to your main goroutine.
In order to get the return values for that go routine you must use channels that will wait for the values.
In your case
errChan := make(chan error)
retChan := make(chan SomeStructType)
go func() {
myVal, err := sm.MethodA()
if err != nil {
errChan <- err
return
}
if err := sm.MethodB(); err != nil {
errChan <- err
return
}
retChan <- myVal
}()
select {
case err := <-errChan:
fmt.Println(err)
case val := <-retChan:
fmt.Printf("My value: %v\n", val)
}
You can mess around with it here to make more sense out of it:
http://play.golang.org/p/TtfFIZerhk

Go: Reading and writing compressed gob to file

This does not appear to work correctly and I'm not sure what I'm doing wrong. I'm attempting to convert a map into a gob, gzip the binary and save it to a file, then later read it back.
type Object struct {
mystruct map[string][]scorer
}
type scorer struct {
category int
score float64
}
func (t *Object) Load(filename string) error {
fi, err := os.Open(filename)
if err !=nil {
return err
}
defer fi.Close()
fz, err := gzip.NewReader(fi)
if err !=nil {
return err
}
defer fz.Close()
decoder := gob.NewDecoder(fz)
err = decoder.Decode(&t.mystruct)
if err !=nil {
return err
}
return nil
}
func (t *Object) Save(filename string) error {
fi, err := os.Create(filename)
if err !=nil {
return err
}
defer fi.Close()
fz := gzip.NewWriter(fi)
defer fz.Close()
encoder := gob.NewEncoder(fz)
err = encoder.Encode(t.mystruct)
if err !=nil {
return err
}
return nil
}
Something is saved to a file and the gzip appears to be valid, but it is either saving nothing or not loading it back again.
I'm also not sure if I'm doing this correctly as I'm new to Go and I'm finding it difficult to get my head around the readers and writers, since I'm coming from PHP and not used to that.
Any ideas?
Your problem has nothing to do with Readers and Writers: You just cannot encode/decode fields which are un-exported and all your fields are unexported (lowercase). You'll have to use Mystruct, Categoryand Score or write your own BinaryMarshal/BinaryUnmarshal as explained in http://golang.org/pkg/encoding/gob/#example__encodeDecode

Resources