Golang动态创建结构体成员

30

我知道Go语言中有结构体,但据我所知,你必须定义结构体。

type Circle struct{
    x,y,r float64
}
我想知道如何声明一个在结构体中不存在的新变量。
circle := new(Circle)
circle.color = "black"
4个回答

62

要使用动态JSON,您需要使用一个类型为map[string]interface{}的映射。以下是创建新映射的示例:

// Initial declaration
m := map[string]interface{}{
    "key": "value",
}

// Dynamically add a sub-map
m["sub"] = map[string]interface{}{
    "deepKey": "deepValue",
}

将JSON反序列化为映射的过程如下:

var f interface{}
err := json.Unmarshal(b, &f)

以上代码将在f中生成一个类似结构的地图:

f = map[string]interface{}{
    "Name": "Wednesday",
    "Age":  6,
    "Parents": []interface{}{
        "Gomez",
        "Morticia",
    },
}
您需要使用类型断言来访问它,否则 Go 将不知道它是一个 map:

您需要使用类型断言来访问它,否则Go将无法识别它为map:

m := f.(map[string]interface{})

你还需要对从地图中获取的每个项使用断言或类型切换。处理非结构化的JSON会很麻烦。

更多信息:


14
这个回答似乎全部都是关于 JSON 的。我在原问题中没有看到任何提到 JSON 的地方。你能否调整回答或编辑问题? 这个回答似乎全部都是关于 JSON 的。我在原问题中没有看到任何提到 JSON 的地方。您能否调整回答或编辑问题? - user1175849

17

我已经开始在这个小仓库上工作https://github.com/Ompluscator/dynamic-struct

目前可以通过传递一个结构体实例并修改字段(添加、删除、更改类型和标签)来在运行时扩展现有的结构体。

仍在进行中,所以不要期望太高 :)

编辑:目前,该库的工作已完成,并且看起来在过去几个月里很稳定 :)


你真是个天才!这个库非常有用。不过还有一件事情缺失。未导出的字段只有在具有PkgPath时才能添加。我的建议是:如果要扩展一个字段,请使用来自“model”的字段(reflect.TypeOf(model).Elem().PkgPath()),对于新结构体,请请求PkgPath或尝试通过堆栈找到它。如果您愿意,这是我快速完成的内容:https://github.com/xdevs23/dynamic-struct/blob/master/builder.go - xdevs23
1
谢谢!我会尝试添加 :) - Marko Milojevic

7
你可以使用反射包来完成此操作,查看 StructOf 方法,它允许你从 []reflect.StructField 创建一个新的结构体。示例代码如下:
func main() {
typ := reflect.StructOf([]reflect.StructField{
    {
        Name: "Height",
        Type: reflect.TypeOf(float64(0)),
        Tag:  `json:"height"`,
    },
    {
        Name: "Age",
        Type: reflect.TypeOf(int(0)),
        Tag:  `json:"age"`,
    },
})

v := reflect.New(typ).Elem()
v.Field(0).SetFloat(0.4)
v.Field(1).SetInt(2)
s := v.Addr().Interface()

w := new(bytes.Buffer)
if err := json.NewEncoder(w).Encode(s); err != nil {
    panic(err)
}

fmt.Printf("value: %+v\n", s)
fmt.Printf("json:  %s", w.Bytes())

r := bytes.NewReader([]byte(`{"height":1.5,"age":10}`))
if err := json.NewDecoder(r).Decode(s); err != nil {
    panic(err)
}
fmt.Printf("value: %+v\n", s)

}


2
你做不到。Go是静态类型的,不允许这样的构造。
结构体在内存中有一个与定义直接相关的布局,没有地方存储这样的额外字段。
你可以使用map代替。此外,你可以将&circle作为键或键的一部分,将map元素与任意结构体关联起来。
type key struct {
    target interface{}
    field string
}

x := make(map[key]string)
x[key{ target: circle, field: "color" }] = "black"

也许我需要重新表达我的问题。假设我想构建一个JSON主体,但我不知道JSON的内部结构是什么样的。那么我该如何创建这样的映射呢? - UniSound Waterloo
1
请访问https://tour.golang.org,了解有关映射和其他许多需要的内容。然后,正如其他人所说,`map[string]interface{}`是JSON对象的类型,其键和值类型未知(而`[]interface{}`是具有未知元素类型的JSON数组)。 - twotwotwo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接