我正在尝试创建一个可以将多种类型的数据(用户、地址等)解析为结构的文件解析器。为此,我创建了一个名为 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/