如何从数组创建Golang结构实例?

时间:2019-12-03 14:34:28

标签: go struct

假设我有一堆字符串数组,例如:

data := [4]string{"a", "3.0", "2.5",  "10.7"}

和一个结构定义:

type Record struct {
  name string
  x  float64
  y  float64
  mag  float64
}

我想从每个数组创建此结构的实例。

我需要将数组的第一项与struct的第一字段进行匹配,依此类推。是否有可能做到这一点? 每个数组对应一个文件的一行,因此我可以实际决定在不同方法更好的情况下如何读取这些值。

3 个答案:

答案 0 :(得分:4)

一种简单的方法是使用反射来遍历该结构的字段,获取其地址(指针),然后使用fmt.Sscan()将字符串值扫描到该字段中。 fmt.Sscan()将为您处理不同类型的字段。这绝不是一个有效的解决方案,它只是一个简短,简单且灵活的解决方案。如果需要有效的解决方案,则必须手动显式处理所有字段。

这仅在导出结构的字段时有效,例如:

type Record struct {
    Name string
    X    float64
    Y    float64
    Mag  float64
    Age  int
}

将字符串切片加载到结构值中的函数:

func assign(recordPtr interface{}, data []string) error {
    v := reflect.ValueOf(recordPtr).Elem()
    max := v.NumField()
    if max > len(data) {
        max = len(data)
    }

    for i := 0; i < max; i++ {
        if _, err := fmt.Sscan(data[i], v.Field(i).Addr().Interface()); err != nil {
            return err
        }
    }

    return nil
}

请注意,此实现尝试填充尽可能多的字段(例如,如果结构的字段多于或少于提供的输入数据,则不会返回错误)。还要注意,此assign()函数可以填充任何其他结构,而不仅仅是Record,这就是为什么它很灵活的原因。

测试示例:

data := []string{"a", "3.0", "2.5", "10.7", "23"}

var r Record
if err := assign(&r, data); err != nil {
    fmt.Println("error:", err)
}
fmt.Printf("%+v", r)

输出(在Go Playground上尝试):

{Name:a X:3 Y:2.5 Mag:10.7 Age:23}

答案 1 :(得分:1)

没有简单的方法可以做到这一点。您必须一个一地分配结构成员。

for _, x := range data {
    x, err := strconv.ParseFloat(x[1])
    y, err := strconv.ParseFloat(x[2])
    max, err := strconv.ParseFloat(x[3])
    strData = append(strData, Record{name: x[0], x: x, y: y, mag: mag})
}

您还必须处理解析错误。

答案 2 :(得分:0)

当然可以在Go中做到这一点。

以下代码示例将向s分配填充有数据字段的记录。

package main

import (
    "fmt"
    "strconv"
)

type Record struct {
    name string
    x    float64
    y    float64
    mag  float64
}

func main() {
    data := [4]string{"a", "3.0", "2.5", "10.7"}
    x, err :=  strconv.ParseFloat(data[1], 64)
    if err != nil {
        panic(err)
    }
    y, err :=  strconv.ParseFloat(data[2], 64)
    if err != nil {
        panic(err)
    }
    mag, err :=  strconv.ParseFloat(data[3], 64)
    if err != nil {
        panic(err)
    }
    s := Record{ name: data[0], x: x, y: y, mag: mag}

    fmt.Println(s)
}