Golang中如何将任意结构体作为参数传递并返回该结构体

Golang中如何将任意结构体作为参数传递并返回该结构体 你好

我是Go语言的新手,想了解是否有方法可以创建一个接收任意结构体作为参数的函数。我的代码中有五个结构体需要执行完全相同的操作并返回相同结构体,但不确定是否能够实现。我在想是否可以做类似这样的操作:

type Car struct {
         Model    string `yaml:"Model"`
         Color     string `yaml:"Color"`
         Wheels  int      `yaml:Wheels"`
}

type Motorcycle struct {
          Model    string `yaml:"Model"`
         Color     string `yaml:"Color"`
         Wheels  int      `yaml:Wheels"`
}

type Bus struct {
         Model    string `yaml:"Model"`
         Color     string `yaml:"Color"`
         Wheels  int      `yaml:Wheels"`
}

func main () {

        car := GetYamlData(Car)
        motorcycle := GetYamlData(Motorcycle)
        Bus := GetYamlData(Bus)
}

func GetYamlData(struct anyStructure) (ReturnAnyStruct struct){

           yaml.Unmarshal(yamlFile, &anyStructure)

           return anyStructure
}

是否可能实现类似上述代码的功能?实际上我目前的代码是这样的:

func main(){
      car, _, _ := GetYamlData("car")
       _,motorcycle,_ := GetYamlData("motorcycle")
       _,_,bus := GetYamlData("bus")
}

func GetYamlData(structureType string) (car *Car, motorcycle *Motorcycle, bus *Bus){

     switch structureType{

            case "car":
                    yaml.Unmarshal(Filepath, car)
            case "motorcycle":
                    yaml.Unmarshal(Filepath, motorcycle)
            case "bus":
                    yaml.Unmarshal(Filepath, bus)
     }

     return car, motorcycle, bus

}

随着时间的推移,这种情况会不断增加,我不希望有太多的返回值。有没有办法用我发布的第一段代码来实现这个需求?

谢谢!


更多关于Golang中如何将任意结构体作为参数传递并返回该结构体的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

我通过以下方式解决了问题:

func GetYamlData(i interface{}) {
    yaml.Unmarshal(Filepath, i)    
}

更多关于Golang中如何将任意结构体作为参数传递并返回该结构体的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我建议类似以下实现:

func main(){
      var car Car
      var motorcycle Motorcycle
      var bus Bus
      var err error

      if err = GetYamlData("car", &car); err != nil {
           // 处理错误
      }
       if err = GetYamlData("motorcycle", &motorcycle); err != nil [
            // 处理错误
      }
       if err = GetYamlData("bus", &bus); err != nil {
            // 处理错误
      }
}

func GetYamlData(structType string, val interface{}) err {

     switch structureType{

            case "car":
                    return yaml.Unmarshal(Filepath, car.(*Car))
            case "motorcycle":
                    return yaml.Unmarshal(Filepath, motorcycle.(*Motorcycle))
            case "bus":
                    return yaml.Unmarshal(Filepath, bus.(*Bus))
     }

     return fmt.Errorf("未知的结构类型: %s", structType)
}

在Go语言中,可以通过使用interface{}(空接口)和反射(reflection)来实现接收任意结构体作为参数并返回相同类型结构体的功能。以下是实现方法:

package main

import (
    "fmt"
    "gopkg.in/yaml.v2"
    "io/ioutil"
    "reflect"
)

type Car struct {
    Model  string `yaml:"Model"`
    Color  string `yaml:"Color"`
    Wheels int    `yaml:"Wheels"`
}

type Motorcycle struct {
    Model  string `yaml:"Model"`
    Color  string `yaml:"Color"`
    Wheels int    `yaml:"Wheels"`
}

type Bus struct {
    Model  string `yaml:"Model"`
    Color  string `yaml:"Color"`
    Wheels int    `yaml:"Wheels"`
}

func GetYamlData(filepath string, target interface{}) error {
    data, err := ioutil.ReadFile(filepath)
    if err != nil {
        return err
    }
    
    return yaml.Unmarshal(data, target)
}

func main() {
    var car Car
    err := GetYamlData("car.yaml", &car)
    if err != nil {
        fmt.Println("Error:", err)
    }
    fmt.Printf("Car: %+v\n", car)
    
    var motorcycle Motorcycle
    err = GetYamlData("motorcycle.yaml", &motorcycle)
    if err != nil {
        fmt.Println("Error:", err)
    }
    fmt.Printf("Motorcycle: %+v\n", motorcycle)
    
    var bus Bus
    err = GetYamlData("bus.yaml", &bus)
    if err != nil {
        fmt.Println("Error:", err)
    }
    fmt.Printf("Bus: %+v\n", bus)
}

如果需要返回新实例而不是修改传入的参数,可以使用反射来创建结构体的新实例:

func GetYamlDataNew(filepath string, target interface{}) (interface{}, error) {
    // 获取目标类型的反射类型
    targetType := reflect.TypeOf(target)
    if targetType.Kind() == reflect.Ptr {
        targetType = targetType.Elem()
    }
    
    // 创建新的实例
    newInstance := reflect.New(targetType).Interface()
    
    data, err := ioutil.ReadFile(filepath)
    if err != nil {
        return nil, err
    }
    
    err = yaml.Unmarshal(data, newInstance)
    if err != nil {
        return nil, err
    }
    
    return reflect.ValueOf(newInstance).Elem().Interface(), nil
}

func main() {
    // 使用返回新实例的版本
    car, err := GetYamlDataNew("car.yaml", Car{})
    if err != nil {
        fmt.Println("Error:", err)
    }
    fmt.Printf("Car: %+v\n", car)
    
    motorcycle, err := GetYamlDataNew("motorcycle.yaml", Motorcycle{})
    if err != nil {
        fmt.Println("Error:", err)
    }
    fmt.Printf("Motorcycle: %+v\n", motorcycle)
    
    bus, err := GetYamlDataNew("bus.yaml", Bus{})
    if err != nil {
        fmt.Println("Error:", err)
    }
    fmt.Printf("Bus: %+v\n", bus)
}

另一种更类型安全的方法是使用泛型(Go 1.18+):

// Go 1.18+ 使用泛型
func GetYamlDataGeneric[T any](filepath string) (*T, error) {
    var result T
    data, err := ioutil.ReadFile(filepath)
    if err != nil {
        return nil, err
    }
    
    err = yaml.Unmarshal(data, &result)
    if err != nil {
        return nil, err
    }
    
    return &result, nil
}

func main() {
    // 使用泛型版本
    car, err := GetYamlDataGeneric[Car]("car.yaml")
    if err != nil {
        fmt.Println("Error:", err)
    }
    fmt.Printf("Car: %+v\n", car)
    
    motorcycle, err := GetYamlDataGeneric[Motorcycle]("motorcycle.yaml")
    if err != nil {
        fmt.Println("Error:", err)
    }
    fmt.Printf("Motorcycle: %+v\n", motorcycle)
    
    bus, err := GetYamlDataGeneric[Bus]("bus.yaml")
    if err != nil {
        fmt.Println("Error:", err)
    }
    fmt.Printf("Bus: %+v\n", bus)
}

这些方法都可以避免使用多个返回值,并且能够处理任意数量的结构体类型。第一种方法使用接口和反射,兼容性最好;第二种使用泛型,类型安全性更高但需要Go 1.18+版本。

回到顶部