go - 从接口(interface)获取结构值

标签 go

我正在尝试创建一个可以将多种类型的数据(用户、地址等)解析为结构的文件解析器。为此,我创建了一个名为 Datatype 的接口(interface):

package main

type Datatype interface {
  name() string
}

还有几个实现接口(interface)的结构体:

例如

package main

type User struct {
    Username    string `validate:"nonzero"`
    FirstName   string `validate:"nonzero"`
    LastName    string `validate:"nonzero"`
    Email       string `validate:"regexp=^[0-9a-zA-Z]+@[0-9a-zA-Z]+(\\.[0-9a-zA-Z]+)+$"`
    Phone       string `validate:"min=10"`
    DateOfBirth string
}

type Users []User

func (u User) name() string {
    return "user"
}

I then read the filename, get the type of data it contains from the name of the file and create an instance of that struct to pass to the parser:

func Parsefile(file string, dtype Datatype) ([]Datatype, error) {
   // Do stuff in here to parse the file

I did this hoping I could create a parse method that took any one of the structs, detect the type and unmarshall from the csv record. However, what I am finding is that I can't do it this was as I can't seem to get the the underlying type from the interface. Or at least not with my Unmarshall function:

func Unmarshal(reader *csv.Reader, v *Datatype) error {
    record, err := reader.Read()
    fmt.Println("Record: ", record)
    if err != nil {
        return err
    }
    s := reflect.ValueOf(v).Elem()
    if s.NumField() != len(record) {
        return &FieldMismatch{s.NumField(), len(record)}
    }
    for i := 0; i < s.NumField(); i++ {
        f := s.Field(i)
        switch f.Type().String() {
        case "string":
            f.SetString(record[i])
        case "int":
            ival, err := strconv.ParseInt(record[i], 10, 0)
            if err != nil {
                return err
            }
            f.SetInt(ival)
        default:
            return &UnsupportedType{f.Type().String()}
        }
    }
    return nil
}

在上面的函数中,当它遇到试图确定数据类型中的字段数的行时,出现以下错误:

panic: reflect: call of reflect.Value.NumField on interface Value

我知道我在这方面做得不好,我觉得必须有一种方法可以实现这种模式,而不必为每种数据类型编写特定的逻辑。然而,对于我的生活,我无法弄清楚如何在 go 中实现这一目标。

最佳答案

看来您正在尝试使用来自 this question 的 csv 解码代码.当您有一个特定类型的预分配结构要传递给它时,它就可以工作。您遇到问题是因为即使传入的特定值是结构,v 仍然是静态接口(interface)类型。

我建议在您的界面和每个子类型上放置一个 Unmarshal 方法:

func (u *User) populateFrom(reader *csv.Reader) string {
    Unmarshal(reader, u) 
}

go 中另一个很酷的东西是 type switch :

var i interface{}
switch t := v.(type) {
    case *User:
       i := t // i is now a *User.
    case *Address:
       i := t // i is now a *Address.
    default:
       panic("unknown type")
}
Unmarshal(reader,i)

关于go - 从接口(interface)获取结构值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29712513/

相关文章:

go - 没有 "go to definition"也没有 golang 代码的函数定义弹出窗口

go - exec.Command ("date") 找不到日期命令

image - Golang PNG 颜色操作不会达到 255

去测试不会构建 : Call has possible formatting directive

go - 有没有一种方法可以优化该代码? Go中的TCP服务器

go - net包中listen、read和write函数的区别

Go 文件夹结构

arrays - 我可以在 golang for-range 迭代中创建索引 int64 吗?

caching - channel 并发保证

tcp - 不同 Goroutine 中的 ZeroMQ 上下文如何通信?