在 Golang 的一个函数中返回不同结果值之一的正确方法是什么?

What's the correct way of returning one of different result values in one func in Golang?

提问人:George Bagiryan 提问时间:8/6/2023 更新时间:8/6/2023 访问量:90

问:

我是 Go 的新手,希望从更多经验丰富的开发人员那里获得一些见解。

在我的主函数中,我调用一个“Prepare”函数,该函数将枚举作为参数。枚举是三个选项之一:A、B、C。 在函数“PrepareData”中,我有一个开关案例,它根据枚举类型调用相应结构的三种准备方法之一。这些方法中的每一个都返回不同的结构作为结果(typeA、typeB、typeC)。但是“准备”函数的返回值应该是什么?

最干净的意识形态方法是什么? 我知道我可以从“Prepare”函数返回一个 emty 接口,或者使用通用方法创建一个接口并返回它,但这些选项对我来说似乎并不“干净”。我错了吗?我想尽可能地保持强类型,并在“Prepare”功能的结果中有一个具体的类型。泛型或类型断言/强制转换可以成为这里的解决方案吗?任何建议将不胜感激。

下面是一些代码,例如:

type DataType int

const (
    A DataType = iota
    B
    C
)
func main() {
    dataType := C // Type will change in run time. Just an examlpe
    result := Prepare(dataType)
    fmt.Println(result)
}
func Prepare(dataType DataType) interface{} { // return value in the question
    switch dataType {
    case A:
        return TypeA{}.Prepare()
    case B:
        return TypeB{}.Prepare()
    case C:
        return TypeC{}.Prepare()
    default:
        return nil
    }
}
type TypeA struct{}

func (t TypeA) Prepare() *TypeA {
    return &TypeA{}
}
type TypeB struct{}

func (t TypeB) Prepare() *TypeB {
    return &TypeB{}
}
type TypeC struct{}

func (t TypeC) Prepare() *TypeC {
    return &TypeC{}
}
go 泛型类型 转换 类型断言

评论

0赞 Paul Hankin 8/6/2023
类型的选择取决于您对结果值的处理方式,因为可能所有代码都需要能够处理三种不同的类型(或基础类型)。如果你要做的只是打印它们,那就没问题了。interface{}
0赞 George Bagiryan 8/6/2023
嗯,是的,这只是一个例子,实际上 Prepare func 的结果将以类似的方式进一步处理。就像想象一下,switch 中的每个情况都会一个接一个地调用几个方法,直到最终返回最终结果
1赞 Volker 8/6/2023
编写 3 个不同的函数 PreapareA、PrepareB 和 PrepareC。
0赞 George Bagiryan 8/6/2023
这是一个显而易见的选择,但与我的问题关系不大。问题是如何从 Prepare 函数返回正确的类型

答:

1赞 NotX 8/6/2023 #1

Go 不是 TypeScript,它用于灵活打字的手段相当有限。您的选项包括:

  • 返回三个不同的专用函数,正如 @Volker 在评论中已经建议的那样。这是您可以从 Go 中获得的唯一“真实”类型的安全性。而且我真的看不出单个函数有什么优势,它的行为取决于其输入值。如果存在共享代码,请将其提取到单独的实用程序函数中。
  • 返回interface{}/any
  • 返回如下值,稍后可以检查哪个值不是。这是相当臃肿的。structnil
type Result struct {
  ResultA *TypeA
  ResultB *TypeB
  ResultC *TypeC
}
  • 如果它只是三种不同的类型(并且不会变得更多),请以 的方式返回它们,并检查哪个不是 。func Prepare(dataType DataType) (*TypeA, *TypeB, *TypeC) {...nil

我个人使用三个专用函数,或者可能使用 /。请注意,如果选择后者,则有一种相当直接的模式来处理使用类型开关的不同预期类型interface{}any

switch v:=result.(type) {
case TypeA, *TypeA:
    v.SpecificTypeAFunction()
case TypeV, *TypeB:
    v.SpecificTypeBFunction()
case TypeC, *TypeC:
    v.SpecificTypeCFunction()
default:
    panic(fmt.Errorf("result is of type %T, which is not supported yet", result))
}

评论

1赞 George Bagiryan 8/6/2023
谢谢,这很有帮助,我想我会使用单独的功能。我只是希望有一种干净的方法来调用单个函数,但考虑到每种情况下的函数参数都不同,这可能不是明智的方法。