Returning a pointer to a struct from a function in Go

huangapple go评论68阅读模式
英文:

Returning a pointer to a struct from a function in Go

问题

我有两个包含不同数据的公共结构体,还有一个包含这两个公共结构体之一的私有中间结构体。我还有一个函数,用于解组中间结构体,确定它包含哪个公共结构体,并返回其中一个公共结构体。

我面临的问题是最后一个函数的返回值。最简单的情况下,我认为可以返回*struct{},但是我的IDE中一直出现类型不匹配的错误。

对于我发布的代码可能比必要的多,我表示歉意,但我试图使其尽可能接近我正在处理的代码。

package main

import (
	"encoding/json"
	"errors"
)

// 这些变量是我稍后在函数中使用的一些错误
var (
	errInvalidBase64     = errors.New("invalid base64")
	errInvalidStructType = errors.New("invalid struct type")
)

// Struct1 公共结构体
type Struct1 struct {
	FName string `json:"first-name"`
	LName string `json:"last-name"`
}

// Struct2 公共结构体
type Struct2 struct {
	Date  string `json:"date"`
	Items []int  `json:"items"`
}

// intermediateStruct 私有结构体
// Type 字段指示 intermediateStruct 包含的结构体类型(Struct1 或 Struct2)
// Data 字段包含之前已编组为 JSON 的 Struct1 或 Struct2
type intermediateStruct struct {
	Type structType
	Data []byte
}

// 以下类型和常量是我对 Go 中枚举的理解

// structType 是 intermediateStruct 包含的结构体类型的私有类型
type structType int

// 这些公共常量只是为了避免手动提供不同结构体类型的值
const (
	StructType1 structType = iota
	StructType2
)

// unmarshalStruct1 将 JSON []byte 解组为新的 Struct1,并返回指向该结构体的指针
func unmarshalStruct1(b []byte) (*Struct1, error) {
	newStruct1 := new(Struct1)
	err := json.Unmarshal(b, newStruct1)
	if err != nil {
		return nil, errInvalidBase64
	}
	return newStruct1, nil
}

// unmarshalStruct2 将 JSON []byte 解组为新的 Struct2,并返回指向该结构体的指针
func unmarshalStruct2(b []byte) (*Struct2, error) {
	newStruct2 := new(Struct2)
	err := json.Unmarshal(b, newStruct2)
	if err != nil {
		return nil, errInvalidBase64
	}
	return newStruct2, nil
}

// receiveStruct 接受一个包含 Struct1 或 Struct2 的 *intermediateStruct
// 此函数需要返回 *Struct1 或 *Struct2 和一个错误
func receiveStruct(iStruct *intermediateStruct) (*struct{}, error) {
	switch iStruct.Type {
	case StructType1:
		struct1, err := unmarshalStruct1(iStruct.Data)
		if err != nil {
			return nil, err
		}
		// 下面这行是我遇到类型不匹配的地方
		return struct1, nil
	case StructType2:
		struct2, err := unmarshalStruct2(iStruct.Data)
		if err != nil {
			return nil, err
		}
		// 下面这行是另一个类型不匹配的地方
		return struct2, nil
	default:
		return nil, errInvalidStructType
	}
}

我知道有一种方法可以实现我想要的效果,只是我缺乏经验/理解来实现。

感谢您提供的任何意见!

英文:

I have two public structs that contain different data, and a private intermediate struct containing either of the two public structs. I also have a function that unmarshalls the intermediate struct, determines which public struct it contains, and returns one of the two public structs.

The problem I'm facing is the return value of the last function. At it's simplest I thought I could return *struct{} but I keep getting a type mismatch in my IDE.

I apologize for posting more code than is probably necessary, but I'm trying to make it as close as possible to the code I'm working on.

package main
import (
"encoding/json"
"errors"
)
// These vars are some errors I'll use in the functions later on
var (
errInvalidBase64     = errors.New("invalid base64")
errInvalidStructType = errors.New("invalid struct type")
)
// Struct1 public struct
type Struct1 struct {
FName string `json:"first-name"`
LName string `json:"last-name"`
}
// Struct2 public struct
type Struct2 struct {
Date  string `json:"date"`
Items []int  `json:"items"`
}
// intermediateStruct private struct
// The Type field indicates which kind of struct Data contains (Struct1 or Struct2)
// The Data field contains either Struct1 or Struct2 which was previously marshalled into JSON
type intermediateStruct struct {
Type structType
Data []byte
}
// The following type and const are my understanding of an enum in Go
// structType is a private type for the type of struct intermediateStruct contains
type structType int
// These public constants are just to keep my hands out of providing values for the different struct types
const (
StructType1 structType = iota
StructType2
)
// unmarshalStruct1 unmarshalls JSON []byte into a new Struct1 and returns a pointer to that struct
func unmarshalStruct1(b []bytes) (*Struct1, error) {
newStruct1 := new(Struct1)
err := json.Unmarshal(b, newStruct1)
if err != nil {
return nil, errInvalidBase64
}
return newStruct1, nil
}
// unmarshalStruct2 unmarshalls JSON []byte into a new Struct2 and returns a pointer to that struct
func unmarshalStruct2(b []bytes) (*Struct2, error) {
newStruct2 := new(Struct2)
err := json.Unmarshal(b, newStruct2)
if err != nil {
return nil, errInvalidBase64
}
return newStruct2, nil
}
// receiveStruct accepts *intermediateStruct who's Data field contains either Struct1 or Struct2
// This function needs to return either *Struct1 or *Struct2 and an error
func receiveStruct(iStruct *intermediateStruct) (*struct{}, error) {
switch iStruct.Type {
case StructType1:
struct1, err := unmarshalStruct1(iStruct.Data)
if err != nil {
return nil, err
}
// The following line is where I'm getting the type mismatch
return struct1, nil
case StructType2:
struct2, err := unmarshalStruct2(iStruct.Data)
if err != nil {
return nil, err
}
// The following line is another type mismatch
return struct2, nil
default:
return nil, errInvalidStructType
}
}

I know there's a way to do what I'm trying to achieve - I just lack the experience/understanding to get there.

Thanks for any and all input!

答案1

得分: 1

你的unmarshallStruct函数返回一个指向Struct1Struct2类型的指针(取决于调用哪个版本的函数)。因此,变量struct1struct2分别是指向Struct1Struct2类型的指针。它们都不是指向结构体类型的指针(我必须补充说明,结构体类型本身并不是Go语言中的真正类型)。结构体是一个关键字,用于声明包含字段/属性的类型。

根据你在代码中的其他用例,你可以尝试以下任何一种方法:
1)如mkopriva建议的那样,返回一个interface{}对象,但你需要使用类型断言来确保对象的类型。
2)定义一个接口,Struct1和Struct2都实现该接口,并返回指向该接口的指针。
3)创建分别适用于Struct1和Struct2的单独函数。这并不一定像听起来那么糟糕,因为Go语言允许你像传递类型一样传递函数(参见sort包中Less()函数的示例)。

英文:

Your unmarshallStruct function returns a pointer to type Struct1 or Struct2 (depending on which version of the function gets called). And therefore the variables struct1 and struct2 are pointers to types Struct1 and Struct2 respectively. Neither is a pointer to type struct (which is not a real Go type anyways I must add). A struct is a keyword which helps to declare types containing fields/attributes.

Depending on the use-cases you have in mind for the rest of your code, can instead try any of the below:

  1. As mkopriva suggested, return a interface{} object, but you'd need to use type assertion to actually make sure of the object
  2. Define an interface which both Struct1 and Struct2 implement, and return a pointer to this
  3. Make separate functions which work with either Struct1 or Struct2. This is not necessarily as bad as it sounds as Go lets you pass functions in the same way you'd pass types (see example of the Less() function in sort package).

huangapple
  • 本文由 发表于 2022年5月11日 00:10:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/72189701.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定