type Product struct {
productName string
}
func (p *Product) GetProductName() string {
return p.productName
}
In Go, how should one typically handle a scenario where the receiver on a method is nil and the method logic itself yields no error (e.g a getter)?
Don't handle it, let it panic
Check for nil and return zero value if true
Check for nil and panic with meaningful message
Check for nil and enhance the method to return error on nil
Other
It really depends
I lean towards #1, but figure that while #3 is a bit verbose it could make debugging easier.
My thoughts are the calling code should be testing for nil and know what to do in such a scenario. That returning an error on a simple getter method is too verbose.
Don't handle it, let it panic
You can see examples in the go standard library. For example, in the net/http package, there is the following:
func (c *Client) Do(req *Request) (*Response, error) {
return c.do(req)
}
And, another example from encoding/json:
// Buffered returns a reader of the data remaining in the Decoder's
// buffer. The reader is valid until the next call to Decode.
func (dec *Decoder) Buffered() io.Reader {
return bytes.NewReader(dec.buf[dec.scanp:])
}
Related
I have this piece of code for example:
type MyStruct struct {
...
MyField *MyOtherStruct
...
}
type MyOtherStruct struct {
...
MyOtherField *string
...
}
// I have a fuction that receive MyOtherField as parameter
func MyFunc(myOtherField *string) {
...
}
// How can I avoid using if/else here
if MyStruct.MyField != nil {
MyFunc((*MyStruct.MyField).MyOtherField)
} else {
MyFunc(nil)
}
In my example, I have to use if else to handle whether MyStruct.MyField is nil or not. I would like to find a way to shorten my code.
I would like to find some way like MyFunc(MyStruct.MyField ? (*MyStruct.MyField).MyOtherField : nil) in JavaScript.
No, you cannot do what you used to do in JS. It is just syntactic sugar. But, there are some alternatives.
First, you can simply write:
if MyStruct.MyField != nil {
MyFunc(MyStruct.MyField.MyOtherField)
} else {
MyFunc(nil)
}
In some cases it may make sense to write getters that work with pointer receivers:
func (m *MyOtherStruct) GetOtherField() *OtherFieldType {
if m==nil {
return nil
}
return m.OtherField
}
Then you can do:
MyFunc(MyStruct.MyField.GetOtherField())
This is how gRPC generates Go models. It is not usually advisable, though. It hides subtle bugs. It is best to be explicit and check where you use it.
GoLang has no 'coalescing nil' operator or ternary conditions (by design, currently at least) but if you want to remove the else from your main flow you can extract it into a helper func.
I've illustrated this as a func with a *MyStruct receiver but it could equally exist as a standalone fun accepting a *MyStruct arg:
func (ms *MyStruct) getMyOtherFieldOrNil() *string {
if ms.MyField == nil {
return nil
}
return ms.MyField.MyOtherField
}
The name of the func makes it clear that a nil result is legitimate, to avoid any potential for confusion.
Then, when you need the MyField.MyOtherField or nil (when MyField is nil) you can use this in place of the if {} else {} construct:
ms := &MyStruct{}
// ...
MyFunc(ms.getMyOtherFieldOrNil())
Footnote
This is similar to Burak's answer but avoids the potential pitfalls of nil receivers which I believe are responsible for the "subtle bugs" mentioned. This slightly higher level helper func will simply panic if called on a nil *MyStruct receiver (as it should), but otherwise achieves much the same purpose.
You cannot avoid using if else. Even through you define a getter for MyStruct, there still if else inside. So I suggest that you should keep your original code for clear.
func TernaryFunc(statement bool, a, b interface{}) interface{} {
if statement {
return a
}
return b
}
MyFunc(TernaryFunc(MyStruct.MyField == nil, (*MyStruct.MyField).MyOtherField, nil).(string))
I'm not sure but try some things like this.
While I am trying to learn Go (version 1.13) I was trying to implement basic network operation but I got tired with if err != nil and decided to be a bit smarter and created something like this
package operation
type Op struct {
err error
result interface{}
}
func Do(supplier func() (interface{}, error)) *Op {
result, err := supplier()
return &Op {result: result, err: err}
}
func (op *Op) onSuccessMap(supplier func(input interface{}) (interface{}, error)) *Op {
if op.err != nil {
return op
} else {
r, e := supplier(op.result)
return &Op{result: r, err: e}
}
}
func (op *Op) onFailure(errorHandler func(error) (interface{}, error)) *Op {
if op.err == nil {
return op
} else {
newResult, err := errorHandler(op.err)
return &Op{result: newResult, err: err}
}
}
func (op *Op) get() (interface{}, error) {
return op.result, op.err
}
and I wanted to call it like
r,e := operation.Do(func()(*http.Request, error){
return http.NewRequest("GET", "http://target.com", nil)
})
.onSuccessMap(func(req *http.Request)(*http.Response, error) {
//... do something with request
})
.onSuccessMap(func(req *http.Response)(MyDomain, error) {
//... do something with response
})
.onFailure(func(e error) (interface{}, error) {
// .. optionally do something with first error
}).get()
but is seems it is not that simple :)
I cannot pass func()(*http.Request, error) where func()(interface{}, error) is expected
anyway Do(func() (string, error) {return "a", nil}.. dont compile either
I actually dont care what is supplied to previous call if next caller can handle it - probably some kind of generics would be handy but I didn't find anything in docs about it.
I cannot call .onSuccessMap/.onXXX/.. probably because I return *Op rather then Op - should I explicitly dereference *Op, maybe I shouldn't return *Op in first place
can I somehow simplify suppliers function so I dont have to pass all those information - it would be nice if compiler figure out what is going on
maybe I think too much in java way and not go way,
any comments/hints will be highly helpful. maybe the whole idea doesn't make sense :]
This Q&A is very much opinion-based, but my suggestion is do not mplement your own error handlers in this fashion.
Since you are you using go 1.13, I would highly recommend you read the new error handling features in the go-blog.
It allows for chaining errors, and easily unwrapping any particular error type from the error-chain. With errors.Is one can determine if a particular error type occurred. With errors.As you can extract the exact details of that error.
fmt.Errorf with %w is a quick way to generate your own wrapped errors. And if you want more error details, you can simply write your own error types provided they include the Error and Wrap interfaces.
I want to extend existing code that writes data to a file in an unbuffered way.
The code expects a writer that implements the io.WriteCloser interface. Therefore just wrapping the existing file with a bufio.Writer does not work, as it does not implement this interface.
How can I make a bufio.Writer to implement and pass the necessary close call to the underlaying file?
io.WriteCloser is the interface:
type WriteCloser interface {
Writer
Closer
}
Which ultimately "prescribes" these 2 methods:
Write(p []byte) (n int, err error)
Close() error
bufio.Writer already has a Write() method, so to make it a WriteCloser, only a Close() method is needed.
Extending bufio.Writer with a noop Close() method:
type MyWriteCloser struct {
*bufio.Writer
}
func (mwc *MyWriteCloser) Close() error {
// Noop
return nil
}
A value of type *MyWriteCloser is now a WriteCloser. This is the easiest extension. Using it:
bw := bufio.NewWriter(w)
mwc := &MyWriteCloser{bw}
Although we can –and we should– add a more meaningful Close() method. As bufio.Write does buffered writes, we should flush its internal buffer before we declare it closed:
func (mwc *MyWriteCloser) Close() error {
return mwc.Flush()
}
Also note that since bufio.Write cannot be closed (does not provide a Close() method), this will not close its underlying io.Writer, this is just to conform to the io.Closer and io.WriteCloser interfaces.
If you also want to close the underlying file, you also have to store it, and after calling bufio.Flush() (to make sure everything is written out), given it's not returning any errors, you may proceed to also close the file.
This is how it could look like:
type MyWriteCloser struct {
f *os.File
*bufio.Writer
}
func (mwc *MyWriteCloser) Close() error {
if err := mwc.Flush(); err != nil {
return err
}
return mwc.f.Close()
}
Using it:
// Open a file:
f, err := os.Open("myfile.txt")
if err != nil {
panic(err) // Handle error
}
mwc := &MyWriteCloser{f, bufio.NewWriter(f)}
defer mwc.Close()
// use mwc
Let's say I have this interface
type Selecter interface {
Select(vars ...string) error
}
and I want to make handlers that pretty much just return JSON forms of that interface after it has called the Select function. Like this:
func MakeHandler(s Selecter) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
//... do some stuff to get vars ...
if err := s.Select(v1, v2); err != nil {
//... blah blah errors ...
}
b, err := json.Marshal(s)
if err != nil {
//... blah blah errors ...
}
w.Write(b)
}
}
So if CoolType is a Selecter I can do something like this
type CoolType struct {
CoolString string `json:"cool_string"`
CoolInt int `json:"cool_int"`
CoolBool bool `json:"cool_bool"`
}
func (c *CoolType) Select(vars ...string) error {
// fill up c using vars
return nil
}
// this looks kinda ugly to me too
fn := MakeHandler(CoolType{})
The underlying problem I have with this is that s is an interface and uses a pointer. This would make this not safe in goroutines since s could be modified between the calls to Select and the call to Marshal.
I really think this is the way I'd like to go about implementing this since it is fairly concise and easy for me to change, but I think I'm missing something. I could use reflect or change the Selecter interface to have Select return an interface{} instead since I don't particularly care what the type is. Then I'd just make a new copy of the type in every implementation of Select I guess. Or a mutex would work. Or perhaps the better way to do this would be to have all of my Selecter types just implement ServeHTTP and be an http.Handler.
Anyway I assume people have tried something like this and have come up with possibly more elegant solutions so I'd like to hear some ideas.
If you are afraid of mutations pass a copy of the value. To do it you probably have to change your interface to something like:
type Selecter interface {
Select(vars ...string) (Selecter, error)
}
And change your Select method to take a value receiver to fulfill the interface. It would be func (c CoolType) Select(vars ...string) (CoolType, error)
Then pass your s as a value instead of pointer and call Select like:
if s, err := s.Select(v1, v2); err != nil {
//... blah blah errors ...
}
You can argue that you lose information about the type, but you already lost it while passing the value as a Selecter interface.
But in general your implementation is good. My feeling is that in Go elegant is something different than in other languages. I'd say that in Go elegant is readable, maintainable and accurate - not bureaucracy and trying to protect you from yourself.
Due to error handling in Go, I often end up with multiple values functions. So far, the way I have managed this has been very messy and I am looking for best practices to write cleaner code.
Let's say I have the following function:
type Item struct {
Value int
Name string
}
func Get(value int) (Item, error) {
// some code
return item, nil
}
How can I assign a new variable to item.Value elegantly. Before introducing the error handling, my function just returned item and I could simply do this:
val := Get(1).Value
Now I do this:
item, _ := Get(1)
val := item.Value
Isn't there a way to access directly the first returned variable?
In case of a multi-value return function you can't refer to fields or methods of a specific value of the result when calling the function.
And if one of them is an error, it's there for a reason (which is the function might fail) and you should not bypass it because if you do, your subsequent code might also fail miserably (e.g. resulting in runtime panic).
However there might be situations where you know the code will not fail in any circumstances. In these cases you can provide a helper function (or method) which will discard the error (or raise a runtime panic if it still occurs).
This can be the case if you provide the input values for a function from code, and you know they work.
Great examples of this are the template and regexp packages: if you provide a valid template or regexp at compile time, you can be sure they can always be parsed without errors at runtime. For this reason the template package provides the Must(t *Template, err error) *Template function and the regexp package provides the MustCompile(str string) *Regexp function: they don't return errors because their intended use is where the input is guaranteed to be valid.
Examples:
// "text" is a valid template, parsing it will not fail
var t = template.Must(template.New("name").Parse("text"))
// `^[a-z]+\[[0-9]+\]$` is a valid regexp, always compiles
var validID = regexp.MustCompile(`^[a-z]+\[[0-9]+\]$`)
Back to your case
IF you can be certain Get() will not produce error for certain input values, you can create a helper Must() function which would not return the error but raise a runtime panic if it still occurs:
func Must(i Item, err error) Item {
if err != nil {
panic(err)
}
return i
}
But you should not use this in all cases, just when you're sure it succeeds. Usage:
val := Must(Get(1)).Value
Go 1.18 generics update: Go 1.18 adds generics support, it is now possible to write a generic Must() function:
func Must[T any](v T, err error) T {
if err != nil {
panic(err)
}
return v
}
This is available in github.com/icza/gog, as gog.Must() (disclosure: I'm the author).
Alternative / Simplification
You can even simplify it further if you incorporate the Get() call into your helper function, let's call it MustGet:
func MustGet(value int) Item {
i, err := Get(value)
if err != nil {
panic(err)
}
return i
}
Usage:
val := MustGet(1).Value
See some interesting / related questions:
How to pass multiple return values to a variadic function?
Return map like 'ok' in Golang on normal functions
Yes, there is.
Surprising, huh? You can get a specific value from a multiple return using a simple mute function:
package main
import "fmt"
import "strings"
func µ(a ...interface{}) []interface{} {
return a
}
type A struct {
B string
C func()(string)
}
func main() {
a := A {
B:strings.TrimSpace(µ(E())[1].(string)),
C:µ(G())[0].(func()(string)),
}
fmt.Printf ("%s says %s\n", a.B, a.C())
}
func E() (bool, string) {
return false, "F"
}
func G() (func()(string), bool) {
return func() string { return "Hello" }, true
}
https://play.golang.org/p/IwqmoKwVm-
Notice how you select the value number just like you would from a slice/array and then the type to get the actual value.
You can read more about the science behind that from this article. Credits to the author.
No, but that is a good thing since you should always handle your errors.
There are techniques that you can employ to defer error handling, see Errors are values by Rob Pike.
ew := &errWriter{w: fd}
ew.write(p0[a:b])
ew.write(p1[c:d])
ew.write(p2[e:f])
// and so on
if ew.err != nil {
return ew.err
}
In this example from the blog post he illustrates how you could create an errWriter type that defers error handling till you are done calling write.
No, you cannot directly access the first value.
I suppose a hack for this would be to return an array of values instead of "item" and "err", and then just do
item, _ := Get(1)[0]
but I would not recommend this.
How about this way?
package main
import (
"fmt"
"errors"
)
type Item struct {
Value int
Name string
}
var items []Item = []Item{{Value:0, Name:"zero"},
{Value:1, Name:"one"},
{Value:2, Name:"two"}}
func main() {
var err error
v := Get(3, &err).Value
if err != nil {
fmt.Println(err)
return
}
fmt.Println(v)
}
func Get(value int, err *error) Item {
if value > (len(items) - 1) {
*err = errors.New("error")
return Item{}
} else {
return items[value]
}
}
Here's a generic helper function with assumption checking:
func assumeNoError(value interface{}, err error) interface{} {
if err != nil {
panic("error encountered when none assumed:" + err.Error())
}
return value
}
Since this returns as an interface{}, you'll generally need to cast it back to your function's return type.
For example, the OP's example called Get(1), which returns (Item, error).
item := assumeNoError(Get(1)).(Item)
The trick that makes this possible: Multi-values returned from one function call can be passed in as multi-variable arguments to another function.
As a special case, if the return values of a function or method g are equal in number and individually assignable to the parameters of another function or method f, then the call f(g(parameters_of_g)) will invoke f after binding the return values of g to the parameters of f in order.
This answer borrows heavily from existing answers, but none had provided a simple, generic solution of this form.