do I always have to return a value even on error - go

If I have a function that looks like this
func ThisIsMyComplexFunc() (ComplexStruct, error)
where ComplexStruct is a big struct that usually contain loads of values.
What if the function stumbles on an error right in the beginning, before I even started building my struct, ideally I would like to only return the error, e.g.
return nil, err
but it wont let me do it, it forces me to create a dummy complex struct and return that together with the error, even though I never want to use the struct.
Is there a way around this?

If your function is declared to return two values, then you will need to return two values.
One option that might simplify your code is to use named return values:
func ThisIsMyComplexFunc() (s ComplexStruct, err error) {
...
}
Now you can just assign to s and/or err and then use a bare return statement. You will still be returning a ComplexStruct value, but you don't need to initialise it manually (it will default to a zero value).

You can return a pointer to the struct:
func ThisIsMyComplexFunc() (*ComplexStruct, error) {
...
if somethingIsWrong {
return nil, err
}
...
return &theStructIBuilt, nil
}
In general, it'll be cheaper to pass big structs by pointer anyway, because it's easier to copy a pointer than the whole struct.

Related

Understanding GO variable assignment

I'm new to GO and trying to build functions with the aws-sdk I have something like this
input := &rds.CreateDBClusterSnapshotInput{
// removed for brevity
}
result, err := svc.CreateDBClusterSnapshot(input)
if err != nil {
// removed for brevity
}
input = &rds.ModifyDBClusterSnapshotAttributeInput{
// removed for brevity
}
When I try to build, I get this error
cannot use &rds.ModifyDBClusterSnapshotAttributeInput literal (type *rds.ModifyDBClusterSnapshotAttributeInput) as type *rds.CreateDBClusterSnapshotInput in assignment
What's wrong with my assignment?
As #Sergio Tulentsev pointed out, you are assigning ModifyDBClusterSnapshotAttributeInput type to the variable input, that is a CreateDBClusterSnapshotInput type.
There would be a few solutions to handle this problem, but the easiest way would be to make a method for each type struct that returns a compatible type for input like this;
func (createInput CreateDBClusterSnapshotInput) ReturnInput() {
return createInput.input // assuming that there are a input type your create
}
If you don't want to make a method with the same functionality for each struct, you can create a base type, make your two structs extend the type, and build a method for the base type.

Passing pointer to string when the function takes an interface?

I am passing a pointer to a string, to a method which takes an interface (I have multiple versions of the method, with different receivers, so I am trying to work with empty interfaces, so that I don't end up with a ton of boilerplate madness. Essentially, I want to populate the string with the first value in the slice. I am able to see the value get populated inside the function, but then for some reason, in my application which calls it, tha value doesn't change. I suspect this is some kind of pointer arithmetic problem, but could really use some help!
I have the following interface :
type HeadInterface interface{
Head(interface{})
}
And then I have the following functions :
func Head(slice HeadInterface, result interface{}){
slice.Head(result)
}
func (slice StringSlice) Head(result interface{}){
result = reflect.ValueOf(slice[0])
fmt.Println(result)
}
and... here is my call to the function from an application which calls the mehtod...
func main(){
test := x.StringSlice{"Phil", "Jessica", "Andrea"}
// empty result string for population within the function
var result string = ""
// Calling the function (it is a call to 'x.Head' because I lazily just called th import 'x')
x.Head(test, &result)
// I would have thought I would have gotten "Phil" here, but instead, it is still empty, despite the Println in the function, calling it "phil.
fmt.Println(result)
}
*NOTE : I am aware that getting the first element doesn't need to be this complicated, and could be slice[0] as a straight assertion, but this is more of an exercise in reusable code, and also in trying to get a grasp of pointers, so please don't point out that solution - I would get much more use out of a solution to my actual problem here * :)
As you said in your NOTE, I'm pretty sure this doesn't have to be this complicated, but to make it work in your context:
package main
import (
"fmt"
"reflect"
)
type HeadInterface interface {
Head(interface{})
}
func Head(slice HeadInterface, result interface{}) {
slice.Head(result)
}
type StringSlice []string
func (slice StringSlice) Head(result interface{}) {
switch result := result.(type) {
case *string:
*result = reflect.ValueOf(slice[0]).String()
fmt.Println("inside Head:", *result)
default:
panic("can't handle this type!")
}
}
func main() {
test := StringSlice{"Phil", "Jessica", "Andrea"}
// empty result string for population within the function
var result string = ""
// Calling the function (it is a call to 'x.Head' because I lazily just called th import 'x')
Head(test, &result)
// I would have thought I would have gotten "Phil" here, but instead, it is still empty, despite the Println in the function, calling it "phil.
fmt.Println("outside:", result)
}
The hard part about working with interface{} is that it's hard to be specific about a type's behavior given that interface{} is the most un-specific type. To modify a variable that you pass as a pointer to a function, you have to use the asterisk (dereference) (for example *result) on the variable in order to change the value it points to, not the pointer itself. But to use the asterisk, you have to know it's actually a pointer (something interface{} doesn't tell you) so that's why I used the type switch to be sure it's a pointer to a string.

Empty return in func with return value in golang [duplicate]

This question already has answers here:
How does defer and named return value work?
(3 answers)
Closed 5 years ago.
I was reading some code written in Golang on Github and found a very interesting piece of code. I simplified it to be clear.
func Insert(docs ...interface{}) (err error) {
for i := 0; i < 3; i++ {
err = fmt.Errorf("")
if err.Error()!="EOF" {
return
}
}
return
}
I'm very confused about empty return here... How it works? Does he return nil as error or breaks for loop? I understand that this question looks dummy, but I cannot find any info on this in go docs... Also, I don't understand how we can return err, which is, as I understood, declared somehow in return. Does (err error) means that we already have an error variable available in our func which is used as default return value if none specified? Why then we implicitly make return err at the end of func?
I'll be very gratefull for explanation.
The function uses a "named" return value.
From the spec on return statements:
The expression list may be empty if the function's result type
specifies names for its result parameters. The result parameters act
as ordinary local variables and the function may assign values to them
as necessary. The "return" statement returns the values of these
variables.
Regardless of how they are declared, all the result values are
initialized to the zero values for their type upon entry to the
function. A "return" statement that specifies results sets the result
parameters before any deferred functions are executed.
Using named returns allows you to save some code on manually allocating local variables, and can sometimes clean up messy if/else statements or long lists of return values.
func a()(x []string, err error){
return
}
is really just shorthand for
func a() ([]string,error){
var x []string
var err error
return x,err
}
Its a bit shorter, and I agree that it may be less obvious.
Named returns are sometimes needed, as it allows things like accessing them inside a deferred function, but the naked return is just syntactic sugar as far as I can tell, and is never strictly required.
One place I see it commonly is in error return cases in functions that have many return values.
if(err != nil){
return
}
return a,b,c,nil
is easier than
if(err != nil){
return nil,nil,nil,err
}
return a,b,c,nil
when you have to write it a bunch of times. And you don't have to modify those returns if you change the signature to have additional "real" return values.
Most places I am using them in the codebase I just searched, they definitely seem to be hiding other smells, like overly complex multi-purpose functions, too deep if/else nesting and stuff like that.
Go's return values may be named. If so, they are treated as variables defined at the top of the function.
package main
import "fmt"
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return
}
func main() {
fmt.Println(split(17))
}
https://tour.golang.org/basics/7
When you have a named return value (err here):
func Insert(docs ...interface{}) (err error) {
This creates a function-local variable by that name, and if you just call return with no parameters, it returns the local variable. So in this function,
return
Is the same as, and implies,
return err
This is detailed in the tour and in the spec.

Using empty interfaces in go

I am trying to understand the code that is used at my company. I am new to go lang, and I have already gone through the tutorial on their official website. However, I am having a hard time wrapping my head around empty interfaces, i.e. interface{}. From various sources online, I figured out that the empty interface can hold any type. But, I am having a hard time figuring out the codebase, especially some of the functions. I will not be posting the entire thing here, but just the minimal functions in which it has been used. Please bear with me!
Function (I am trying to understand):
func (this *RequestHandler) CreateAppHandler(rw http.ResponseWriter, r *http.Request) *foo.ResponseError {
var data *views.Data = &views.Data{Attributes: &domain.Application{}}
var request *views.Request = &views.Request{Data: data}
if err := json.NewDecoder(r.Body).Decode(request); err != nil {
logrus.Error(err)
return foo.NewResponsePropogateError(foo.STATUS_400, err)
}
requestApp := request.Data.Attributes.(*domain.Application)
requestApp.CreatedBy = user
Setting some context, RequestHandler is a struct defined in the same package as this code. domain and views are seperate packages. Application is a struct in the package domain. The following two structs are part of the package views:
type Data struct {
Id string `json:"id"`
Type string `json:"type"`
Attributes interface{} `json:"attributes"`
}
type Request struct {
Data *Data `json:"data"`
}
The following are part of the package json:
func NewDecoder(r io.Reader) *Decoder {
return &Decoder{r: r}
}
func (dec *Decoder) Decode(v interface{}) error {
if dec.err != nil {
return dec.err
}
if err := dec.tokenPrepareForDecode(); err != nil {
return err
}
if !dec.tokenValueAllowed() {
return &SyntaxError{msg: "not at beginning of value"}
}
// Read whole value into buffer.
n, err := dec.readValue()
if err != nil {
return err
}
dec.d.init(dec.buf[dec.scanp : dec.scanp+n])
dec.scanp += n
// Don't save err from unmarshal into dec.err:
// the connection is still usable since we read a complete JSON
// object from it before the error happened.
err = dec.d.unmarshal(v)
// fixup token streaming state
dec.tokenValueEnd()
return err
}
type Decoder struct {
r io.Reader
buf []byte
d decodeState
scanp int // start of unread data in buf
scan scanner
err error
tokenState int
tokenStack []int
}
Now, I understood that, in the struct Data in package views, Application is being set as a type for the empty interface. After that, a pointer to Request in the same package is created which points to the variable data.
I have the following doubts:
What exactly does this keyword mean in Go? What is the purpose of writing this * RequestHandler?
Initialization of a structure in Go can be done while assigning it to a variable by specifying the values of all it's members. However, here, for the struct Data, only the empty interface value is assigned and the values for the other two fields are not assigned?
What is the advantage of assigning the Application struct to an empty interface? Does it mean I can use the struct members using the interface variable directly?
Can someone help me figure out the meaning of this statement? json.NewDecoder(r.Body).Decode(request)?
While I know this is too much, but I am having a hard time figuring out the meaning of interfaces in Go. Please help!
this is not a keyword in go; any variable name can be used there. That is called the receiver. A function declared in that way must be called like thing.func(params), where "thing" is an expression of the type of the receiver. Within the function, the receiver is set to the value of thing.
A struct literal does not have to contain values for all the fields (or any of them). Any fields not explicitly set will have the zero value for their types.
As you said, an empty interface can take on a value of any type. To use a value of type interface{}, you would use type assertion or a type switch to determine the type of the value, or you could use reflection to use the value without having to have code for the specific type.
What specifically about that statement do you not understand? json is the name of a package in which the function NewDecoder is declared. That function is called, and then the Decode function (which is implemented by the type of the return value of NewDecoder) is called on that return value.
You may want to take a look at Effective Go and/or The Go Programming Language Specification for more information.

Pass a result from multi-returing function to another one taking only one argument in Go

Is it possible to pass a result form function which returns multiple values directly to function which accepts only one? Example:
func MarshallCommandMap(mapToMarshall map[string]string) string {
return string(json.Marshal(mapToMarshall))
}
The example above will cause compilation error:multiple-value json.Marshal() in single-value context. I know it is possible to get same result with additional variable:
func MarshallCommandMap(mapToMarshall map[string]string) string {
marshaledBytes, marshalingError := json.Marshal(mapToMarshall)
if (marshalingError != nil) {
panic(marshalingError)
}
return string(marshaledBytes)
}
But is it possible to pass only first value direclty without any variable?
I think you mean doing something like python's tuple unpacking.
Unfortunately this is not possible in Go (AFAIK).
No you can't, however 2 things with your code.
Shouldn't panic, either return an error or return an empty string.
You can make it shorter.
Example :
func MarshallCommandMap(mapToMarshall map[string]string) string {
js, _ := json.Marshal(mapToMarshall) //ignore the error
return string(js)
}

Resources