gpt4 book ai didi

go - 如何使用接口(interface)联合两个不同的结构?

转载 作者:IT王子 更新时间:2023-10-29 01:54:45 24 4
gpt4 key购买 nike

我有以下代码:

package main

import (
"log"
)

type Data struct {
Id int
Name string
}

type DataError struct {
Message string
ErrorCode string
}

func main() {
response := Data{Id: 100, Name: `Name`}
if true {
response = DataError{Message: `message`, ErrorCode: `code`}
}
log.Println(response)
}

此代码返回一个错误:

./start.go:20: cannot use DataError literal (type DataError) as type Data in assignment

似乎是我无法分配给具有不同类型的response var 数据(在我的例子中是DataError)。我听说可能的解决方案是通过接口(interface)联合 DataDataError 结构。或者也许还有其他更好的解决方案?

你能告诉我如何解决这个问题吗?

谢谢

最佳答案

看起来您正在尝试创建一个联合类型(ML 语言家族称之为“枚举”)。我知道有几种模式:

<强>0。基本错误处理 ( playground )

我怀疑您所做的只是基本的错误处理。在 Go 中,我们使用多个返回值并检查结果。这几乎肯定是您想要做的:

package main

import (
"fmt"
"log"
)

type Data struct {
ID int
Name string
}

type DataError struct {
Message string
ErrorCode string
}

// Implement the `error` interface. `error` is an interface with
// a single `Error() string` method
func (err DataError) Error() string {
return fmt.Sprintf("%s: %s", err.ErrorCode, err.Message)
}

func SomeFunction(returnData bool) (Data, error) {
if returnData {
return Data{ID: 42, Name: "Answer"}, nil
}
return Data{}, DataError{
Message: "A thing happened",
ErrorCode: "Oops!",
}
}

func main() {
// this bool argument controls whether or not an error is returned
data, err := SomeFunction(false)
if err != nil {
log.Fatalln(err)
}
fmt.Println(data)
}

<强>1。接口(interface) ( playground )

同样,如果您的选项是好数据和错误,您可能应该使用第一种情况(坚持惯用语/惯例),但其他时候您可能有多个“好数据”选项。我们可以使用接口(interface)来解决这个问题。在这里,我们添加了一个虚拟方法来告诉编译器将可以实现此接口(interface)的可能类型限制为具有 IsResult() 方法的类型。这样做的最大缺点是将东西粘贴到接口(interface)中会导致分配,这在紧密循环中可能是有害的。这种模式并不常见。

package main

import "fmt"

type Result interface {
// a dummy method to limit the possible types that can
// satisfy this interface
IsResult()
}

type Data struct {
ID int
Name string
}

func (d Data) IsResult() {}

type DataError struct {
Message string
ErrorCode string
}

func (err DataError) IsResult() {}

func SomeFunction(isGoodData bool) Result {
if isGoodData {
return Data{ID: 42, Name: "answer"}
}
return DataError{Message: "A thing happened", ErrorCode: "Oops!"}
}

func main() {
fmt.Println(SomeFunction(true))
}

<强>2。标记联盟 ( playground )

这种情况与前面的情况类似,除了我们不使用接口(interface),而是使用带有标记的结构,该标记告诉我们该结构包含哪种类型的数据(这类似于 C 中的标记联合,除了结构的大小是其潜在类型的总和,而不是其最大潜在类型的大小)。虽然这会占用更多空间,但它可以很容易地进行堆栈分配,从而使其成为紧密循环友好的(我已经使用这种技术将分配从 O(n) 减少到 O(1))。在这种情况下,我们的标签是 bool,因为我们只有两种可能的类型(Data 和 DataError),但您也可以使用类似 C 的枚举。

package main

import (
"fmt"
)

type Data struct {
ID int
Name string
}

type DataError struct {
Message string
ErrorCode string
}

type Result struct {
IsGoodData bool
Data Data
Error DataError
}

// Implements the `fmt.Stringer` interface; this is automatically
// detected and invoked by fmt.Println() and friends
func (r Result) String() string {
if r.IsGoodData {
return fmt.Sprint(r.Data)
}
return fmt.Sprint(r.Error)
}

func SomeFunction(isGoodData bool) Result {
if isGoodData {
return Result{
IsGoodData: true,
Data: Data{ID: 42, Name: "Answer"},
}
}
return Result{
IsGoodData: false,
Error: DataError{
Message: "A thing happened",
ErrorCode: "Oops!",
},
}
}

func main() {
// this bool argument controls whether or not an error is returned
fmt.Println(SomeFunction(true))
}

关于go - 如何使用接口(interface)联合两个不同的结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39725223/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com