在Go语言中对于结构体返回nil

61

我正在连接到数据库,获取一行数据并将其发送回给用户。但是,如果我找不到该行数据或出现错误,我想使用return语句。

由于我正在返回一个结构体,因此我无法返回nil,并且会得到错误消息cannot use nil as type Item in return argument(Item是我的结构体)

我在网上看到,如果在返回语句中使用指针并返回*Item而不是Item,那么我就可以传递nil。当我尝试创建item := *Item{}时,我收到以下错误消息:invalid indirect of Item literal (type Item)

我认为有几种解决方案,但我找不到任何一种。我真正想知道的是:

  • 如何返回指针*Item而不是Item
  • 是否有其他方法可以返回结构体的nil值?

这是我的代码:

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)
}

1
item := *Item{} should be item := &Item{} - Elias Van Ootegem
1个回答

84

您的变量item赋值方式不正确。您说您尝试使用的是item := *Item{},而创建指针的方式可以通过使用内置函数new或者创建一个字面值并使用取地址运算符(&)来实现。后一种方式在golang中更为常见。虽然有时候需要使用new,但在这种情况下,我建议使用第二种方法:

因此,可以选择以下两种方式之一:

item := &Item{}
// or
item := new(Item)

最后,您可以保留现有代码,仅在结尾处返回指针:

item := Item{}
// some code here
return &item, nil

在需要返回错误的情况下,您仍然可以使用return nil, err。将所有内容放在一起:
// 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
}

或者,将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
}

2
这可能很明显,但为了确保,OP还应该在Handler的声明中将返回类型从Item更新为*Item - mkopriva
1
@mkopriva:已更新,包含“UnmarshalMap”部分,因此根据变量的初始化方式正确传递了item - Elias Van Ootegem
1
有人能解释一下为什么不能仅仅返回 nil, err 而不先声明 item := &Item{} 或者 item := Item{} 吗? - Rylan Schaeffer
2
因为item作为参数传递给了UnmarshalMap,如果你不声明它,就不能使用它(即将其作为参数传递)。在使用之前需要定义这个变量。如果你不想分配任何内存,除非必须这样做,只需将item := Item{}替换为var item Item,将其作为&item传递给UnmarshalMap调用,并在成功时返回&item,错误时返回nilvar item Item不会分配对象,除非需要,这在语言规范中有提到。 - Elias Van Ootegem
1
@RylanSchaeffer 不错。var item T 这就是我的答案 :-) - ADM-IT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接