【发布时间】:2018-10-31 23:45:47
【问题描述】:
我很难理解 go 中接口和结构之间的关系。我已经声明了一个名为Datatype 的接口,如下所示:
package main
type Datatype interface {
Unmarshal(record []string) error
String() string
}
我还创建了几个实现这个接口的结构。这是一个简单的例子:
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
}
问题:
如您所见,我还有一个名为Users 的类型,即[]User。当我尝试从返回类型为 []Datatype 的函数返回此类型时,我收到以下错误消息:
不能在返回参数中使用结果(用户类型)作为类型 []Datatype
我确定我遗漏了一些明显的东西,但在我看来这应该可行。
问题:
有人可以解释为什么它不起作用吗?是否有更好(更惯用)的方法来实现这一最终结果?
【问题讨论】:
-
String()的实现在哪里?请注意,每次为类型设置别名时,它都是一个全新的类型。此外,您的结构和接口在这里没有关系 - 看来您正试图让您的Users类型实现接口。 -
感谢您更新问题 - 您的
String()方法应用于结构User...而不是类型Users(复数..)。 -
我用我的格式修复了一些错误并添加了一个关键的附加方法。那么在用户上实现我的界面是否有意义?我想我可以看到,但我仍然没有理解为什么它不能在用户上实现它并拥有它们的集合。
-
See the FAQ "我可以将 []T 转换为 []interface{} 吗?" (只需将您的
[]users和[]Datatype替换为常见问题解答中的[]T和[]interface{},这是同一个问题。)