当前位置: 首页 > 知识库问答 >
问题:

从接口获取结构体值

广晔
2023-03-14

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

package main

type Datatype interface {
  name() string
}

以及实现接口的几个结构:

前。

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"
}

然后,我读取文件名,从文件名中获取它包含的数据类型,并创建该结构的实例以传递给解析器:

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

我这样做是希望我可以创建一个解析方法,该方法采用任何一个结构,检测类型并从csv记录中解封。然而,我发现我做不到这一点,因为我似乎无法从接口中获取底层类型。或者至少不能使用我的UnMarshall函数:

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
}

在上面的函数中,当它碰到试图确定Datatype中字段数量的行时,我得到以下错误:

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

我知道我在这方面做得很差,我觉得必须有一种方法来实现这种模式,而不必为每种数据类型编写特定的逻辑。然而,我怎么也想不出如何在围棋中做到这一点。

共有1个答案

安经纶
2023-03-14

您似乎正在尝试使用此问题中的csv解组代码。这是设计为在您有一个特定类型的预分配结构要传递给它时工作的。您遇到了问题,因为v是静态接口类型,即使传入的特定值是结构。

我建议在你的接口和每个子类型上放一个 Unmarshal 方法

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

Go 中另一个很酷的东西是类型开关:

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的精华特点即将展开。 结构体定义 上面我们说过Go的指针和C的不同,结构体也是一样的。Go是一门删繁就简的语言,一切令人困惑的特性都必须去掉。 简单来讲,Go提供的结构体就是把使用各种数据类型定义的不同变量组合起来的高级数据类型。闲话不多说,看例子: type Rect struct { width float64 length floa

  • 12.7. 获取结构体字段标识 在4.5节我们使用构体成员标签用于设置对应JSON对应的名字。其中json成员标签让我们可以选择成员的名字和抑制零值成员的输出。在本节,我们将看到如果通过反射机制类获取成员标签。 对于一个web服务,大部分HTTP处理函数要做的第一件事情就是展开请求中的参数到本地变量中。我们定义了一个工具函数,叫params.Unpack,通过使用结构体成员标签机制来让HTTP处理

  • c.h 得到这样的结果: 这似乎不正确, 我正在golang寻找类似的东西:mvar.VI32 谢谢 我的头很痛,不擅长C / C, 这是我的场景,调用一个SDK(带有.so库) c.h 我试着用Go语言调用函数ASFGetActiveFileInfo,如下所示: 得到这个错误: 尝试: 得到这个错误 这个问题有什么解决方案吗? 感谢@peterSO的回答,它工作,但仍然显示错误: 事实非常接近

  • 问题内容: 到目前为止,我使用PyQt类所做的事情: 输出: 使用: 输出: 有没有办法区分它们? 可以使用普通的Python代替PyQt类吗? 如何获得IPv6地址? 问题答案: 您应该使用netifaces。它被设计为跨平台的,并且包含Windows专用代码以及可在不同UNIX / UNIX类平台上工作的各种通用版本。 从netifaces版本0.10.0开始,支持Python3。 使用摘要

  • 本文向大家介绍C#结构实现接口,包括了C#结构实现接口的使用技巧和注意事项,需要的朋友参考一下 示例            

  • 问题内容: 范例: 我想从引用变量中获取接口名称。有没有办法做到这一点? 问题答案: 使用反射,您可以调用返回您的类实现的方法。 为了得到名字