As an example for multi-value return, we use the AWS SDK. This small program creates a SNS Topic.
To see all SNS Topics before and after, use this AWS CLI command:
aws sns list-topics --query "Topics[*].TopicArn"
1 package main
2
3 import (
4 "context"
5 "fmt"
6
7 "github.com/aws/aws-sdk-go-v2/aws"
8 "github.com/aws/aws-sdk-go-v2/config"
9 "github.com/aws/aws-sdk-go-v2/service/sns"
10 )
11
12 func main() {
13 topic := aws.String("go-topic")
14
15 cfg, err := config.LoadDefaultConfig(context.TODO())
16 if err != nil {
17 panic("configuration error, " + err.Error())
18 }
19
20 client := sns.NewFromConfig(cfg)
21
22 parms := &sns.CreateTopicInput{
23 Name: topic,
24 }
25
26 results, err := client.CreateTopic(context.TODO(), parms)
27 if err != nil {
28 panic("sns error, " + err.Error())
29 }
30
31 fmt.Println(*results.TopicArn)
32 }
package main
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/sns"
)
func main() {
topic := aws.String("go-topic")
cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
panic("configuration error, " + err.Error())
}
client := sns.NewFromConfig(cfg)
parms := &sns.CreateTopicInput{
Name: topic,
}
results, err := client.CreateTopic(context.TODO(), parms)
if err != nil {
panic("sns error, " + err.Error())
}
fmt.Println(*results.TopicArn)
}
In line 26 the two return values are copied into the variables results and err. To know how the return values are defined we look at the AWS GO SDK documentation.
With VSCode (and the go plugin), we get the link to the documentation with a mouse over in line 26:
The documentation says:
func (c *Client) CreateTopic(ctx context.Context, params *CreateTopicInput, optFns ...func(*Options)) (*CreateTopicOutput, error)
So we have these two values:
This is the CreateTopicOutput structure:
type CreateTopicOutput struct {
// The Amazon Resource Name (ARN) assigned to the created topic.
TopicArn *string
// Metadata pertaining to the operation's result.
ResultMetadata middleware.Metadata
// contains filtered or unexported fields
}
We get back the TopicArn and some metadata. The TopicArn is the unique id which we can use to manage the topic, like deleting it (see cleanup).
In this example we give the topicname as a fixed string, so we know in advance which value the TopicArn will have. But if we generate a dynamic name, we need the information.
So we can print the TopicArn, because it is a variable inside the result structure pointer:
31 fmt.Println(*results.TopicArn)
The general error handling is that the error variable contains nil if everything is ok.
So this is the error handling:
27 if err != nil {
28 panic("sns error, " + err.Error())
29 }
Usually you don’t use panic, because this ends the program, but you use the error code to the calling function with or without logging some error infos.
if err != nil {
// log something
return err
}
If you have the “two return variable” setup, you return the error code and an empty pointer to the struct:
if err != nil {
// log something
return nil,err
}
At the end of your function, you would return nil as error:
// successfull end of function
return &myStructureVar, nil
}
If you do not use an assigned variable, go will give a warning and will not run. To avoid that you may use ‘_’ as an “forget the value” variable.
Don’t use error return value:
results, _ := client.CreateTopic(context.TODO(), parms)
Copy the program code without line numbers into a file named main.go, then execute the program:
go run main.go
That gives the topic ARN
arn:aws:sns:eu-central-1:555553403305:go-topic
Where 555553403305 is the account number
You can use this arn to delete the topic:
aws sns delete-topic --topic-arn arn:aws:sns:eu-central-1:555553403305:go-topic
Returning a structure and an error has several pros: