Reputation: 4496
I am connecting to a database, getting a row and then sending it back to the user. What I want to do though is have a return
statement if I can't find that row or if I have an error.
Because I'm returning a struct I can't return nil and I get that error cannot use nil as type Item in return argument
(Item is my struct)
I read online that if I use a pointer in the return statement and return *Item instead of Item then I'd be able to pass nil, when I try to create item := *Item{}
I get the following error invalid indirect of Item literal (type Item)
I think there are a few solutions to this but I can't find any, what I really want to know is:
Here's my code:
package main
import (
"fmt"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
)
type Request struct {
Name string `json:"name"`
}
type Item struct {
Name string `json:"name"`
Stock int `json:"stock"`
Price float64 `json:"price"`
}
func Handler(request Request) (Item, error) {
sess, err := session.NewSession(&aws.Config{
Region: aws.String("us-west-2")},
)
// Create DynamoDB client
svc := dynamodb.New(sess)
result, err := svc.GetItem(&dynamodb.GetItemInput{
TableName: aws.String("Inventory"),
Key: map[string]*dynamodb.AttributeValue{
"name": {
S: aws.String(request.Name),
},
},
})
if err != nil {
fmt.Println(err.Error())
// return nil, err
}
item := Item{}
err = dynamodbattribute.UnmarshalMap(result.Item, &item)
if err != nil {
panic(fmt.Sprintf("Failed to unmarshal Record, %v", err))
// return nil, err
}
if item.Name == "" {
fmt.Println("Could not find item")
// return nil, nil
}
fmt.Println("Found item:")
fmt.Println("Name: ", item.Name)
fmt.Println("Stock: ", item.Stock)
fmt.Println("Price: ", item.Price)
return item, nil
}
func main() {
lambda.Start(Handler)
}
Upvotes: 68
Views: 119752
Reputation: 110
But do you need a nil?
I don't know enough about AWS Lambdas to say whether Start
requires a pointer or nil.
But if called APIs don't require it, and you know that you won't need to mutate the return value after the function call, then it might be better to return the zero value of the struct instead of a nil pointer. Admittedly, it's not as pretty looking as a nil in the return statement or comparisons, but it's safer.
But this is opinion.
Side note: mind the function name ending with -er
, because if one ever turns that into a method with an interface, the latter would need to be called Handlerer
if one wanted to stay within Go convention.
Upvotes: 0
Reputation: 76405
You're assigning your item
variable wrong. You said you tried item := *Item{}
, whereas the way to create a pointer is either through the use of the new
builtin, or to create a literal, and the address-of operator (&
). The latter is the approach you'll most commonly see in golang. There are some cases where one would use new
, but in this case, I'd go for the second approach:
So either:
item := &Item{}
// or
item := new(Item)
Lastly, you can keep the code as-is, and just return a pointer at the end:
item := Item{}
// some code here
return &item, nil
In case where you have to return an error, you can still have return nil, err
So putting everything together:
// return *Item instead of Item
func Handler(request Request) (*Item, error) {
// your code here, eg:
item := Item{}
if err := dynamodbattribute.UnmarshalMap(result.Item, &item); err != nil {
return nil, err
}
return &item, nil
}
Alternatively, assign item
as a pointer from the start
func Handler(request Request) (*Item, error) {
// your code here, eg:
item := &Item{}
if err := dynamodbattribute.UnmarshalMap(result.Item, item); err != nil {
return nil, err
}
return item, nil
}
Upvotes: 92