无法理解接口/结构关系

Roc*_*igh 2 struct go

我很难理解go中的接口和结构之间的关系.我已经声明了一个名为Datatype如下的接口:

package main

type Datatype interface {
    Unmarshal(record []string) error
    String() string
}
Run Code Online (Sandbox Code Playgroud)

我还创建了几个实现此接口的结构.这是一个简单的例子:

package main

import (
    "encoding/csv"
    "fmt"
    "gopkg.in/validator.v2"
    "reflect"
    "strconv"
    "time"
)

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

type Users []User

func (u *User) Unmarshal(record []string) error {
    s := reflect.ValueOf(u).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", "int64":
            ival, err := strconv.ParseInt(record[i], 10, 0)
            if err != nil {
                return err
            }
            f.SetInt(ival)
        default:
            return &UnsupportedType{f.Type().String()}
        }
    }
    return nil
}

func (u *User) String() string {
    return fmt.Sprintf("%#v", u)
}

func (u *User) populateFrom(reader *csv.Reader) (Users, error) {
    var users Users
    for {
        record, err := reader.Read()
        check(err)
        err = u.Unmarshal(record)
        check(err)
        valid := validator.Validate(u)
        if valid == nil {
            user := *u
            users = append(users, user)
        } else {
            fmt.Println("Validation error?: ", valid)
        }
    }
    return users, nil
}
Run Code Online (Sandbox Code Playgroud)

问题:

正如你所看到的,我也有一种被称为Users这仅仅是[]User.当我尝试从返回类型为的函数返回此类型时[]Datatype,我收到以下错误消息:

不能使用结果(类型用户)作为返回参数的类型[]数据类型

我敢肯定我错过了一些明显的东西,但在我看来这应该有效.

题:

有人可以解释为什么它不起作用?是否有更好的(更惯用的)方法来实现这个最终结果?

rua*_*akh 8

切片不协变; 即使User实现Datatype,[]User也没有实现[]Datatype(因为没有实现[]Datatype:它本身不是接口类型,它只是一个切片类型,其元素类型是接口类型).


编辑补充:正如Dave C在上面的评论中指出的那样,Go常见问题解答中出现了一个密切相关的问题.[ 链接 ] Go FAQ以与Stack Exchange内容兼容的方式获得许可,因此,这里是完整的问题:

我可以将[] T转换为[]接口{}吗?

不是直接的,因为它们在内存中没有相同的表示.有必要将元素分别复制到目标切片.此示例将切片转换int为以下切片interface{}:

t := []int{1, 2, 3, 4}
s := make([]interface{}, len(t))
for i, v := range t {
    s[i] = v
}
Run Code Online (Sandbox Code Playgroud)