从接口获取结构值

Am am attempting to create a file parser that can parse multiple types of data (users, addresses, etc) into a struct. To do this I have created an interface called Datatype:

package main

type Datatype interface {
  name() string
}

And several structs that implement the interface:

ex.

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
}

In the above function I get the following error when it hits the line trying to determine the number of fields in the Datatype:

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

I know I am going about this poorly and I feel there must be a way to achieve this pattern without having to write logic specific to each data type. However, for the life of my I cannot figure out how to achieve this in go.

It appears you are trying to use the csv unmarshalling code from this question. That is designed to work when you have a pre-allocated struct of a specific type to pass into it. You are having issues because v is statically an interface type even though the particular value passed in is a struct.

I would recommend putting an Unmarshal method on your interface and on each subType:

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

Another cool thing in go is the 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)