Go 在运行时以编程方式创建结构-可能吗?

Go 在运行时以编程方式创建结构-可能吗?,go,struct,reflection,types,Go,Struct,Reflection,Types,在Go中是否可以通过编程方式(即不在编译的源代码中)创建结构类型 我们有一个特定的用例,其中一个类型将通过用户定义的元数据创建,因此模式/类型事先是未知的 每一位客户的情况都会有所不同。然后,我们需要为这些服务自动生成REST服务,并将它们持久化到NoSQL后端。 我们还需要为每个字段定义不同的动态验证器,例如强制、正则表达式、最大/最小大小、最大/最小值、对其他类型实例的引用等 我想知道在旅途中是否可能有类似的事情 编辑1: 比如说 来自前端的JSON 后端 编辑:您的编辑显示您想要处理要从G

在Go中是否可以通过编程方式(即不在编译的源代码中)创建结构类型

我们有一个特定的用例,其中一个类型将通过用户定义的元数据创建,因此模式/类型事先是未知的 每一位客户的情况都会有所不同。然后,我们需要为这些服务自动生成REST服务,并将它们持久化到NoSQL后端。 我们还需要为每个字段定义不同的动态验证器,例如强制、正则表达式、最大/最小大小、最大/最小值、对其他类型实例的引用等

我想知道在旅途中是否可能有类似的事情

编辑1:

比如说

来自前端的JSON

后端

编辑:您的编辑显示您想要处理要从Google数据存储中放置/检索的动态对象。为此,完全不需要在运行时创建结构类型,您可以只使用此答案中显示的动态映射:

原来的答案如下

请注意,如果类型在编译时已知,那么最好/最有效的方法是创建类型并编译它们,因此所有内容都是静态的。您可以手动创建类型,也可以使用go generate自动执行该过程

还请注意,您可能不一定需要结构类型来建模动态对象,很多时候映射可能就足够了

如果类型在编译时未知,并且结构类型是必须的,请继续阅读

是的,可以在运行时使用Go的反射创建动态结构类型,特别是使用函数

让我们看一个简单的示例,在运行时创建一个具有名称字符串和年龄int字段的结构类型:

这将在以下位置进行尝试:

例如,如果要定义验证规则,可以使用第三方库。此包用于指定验证规则,也可以使用反射指定结构标记

例如,如果要指定名称必须至少包含3个字符,最多40个,并且只能包含英文字母表中的字母,并且年龄的有效范围为6..100(包括6..100),则如下所示:

t := reflect.StructOf([]reflect.StructField{
    {
        Name: "Name",
        Type: reflect.TypeOf(""), // string
        Tag:  reflect.StructTag(`validate:"min=3,max=40,regexp=^[a-zA-Z]*$"`),
    },
    {
        Name: "Age",
        Type: reflect.TypeOf(0), // int
        Tag:  reflect.StructTag(`validate:"min=6,max=100"`),
    },
})
打印此类型将由我包装输出,请在以下位置尝试:

创建此结构的实例后,可以使用函数对其进行验证,例如:

v := reflect.New(t)
v.Elem().FieldByName("Name").Set(reflect.ValueOf("Bob"))
v.Elem().FieldByName("Age").Set(reflect.ValueOf(12))

if errs := validator.Validate(v.Elem().Interface()); errs != nil {
    // values not valid, deal with errors here
}
编辑:您的编辑显示您想要处理要从Google数据存储中放置/检索的动态对象。为此,完全不需要在运行时创建结构类型,您可以只使用此答案中显示的动态映射:

原来的答案如下

请注意,如果类型在编译时已知,那么最好/最有效的方法是创建类型并编译它们,因此所有内容都是静态的。您可以手动创建类型,也可以使用go generate自动执行该过程

还请注意,您可能不一定需要结构类型来建模动态对象,很多时候映射可能就足够了

如果类型在编译时未知,并且结构类型是必须的,请继续阅读

是的,可以在运行时使用Go的反射创建动态结构类型,特别是使用函数

让我们看一个简单的示例,在运行时创建一个具有名称字符串和年龄int字段的结构类型:

这将在以下位置进行尝试:

例如,如果要定义验证规则,可以使用第三方库。此包用于指定验证规则,也可以使用反射指定结构标记

例如,如果要指定名称必须至少包含3个字符,最多40个,并且只能包含英文字母表中的字母,并且年龄的有效范围为6..100(包括6..100),则如下所示:

t := reflect.StructOf([]reflect.StructField{
    {
        Name: "Name",
        Type: reflect.TypeOf(""), // string
        Tag:  reflect.StructTag(`validate:"min=3,max=40,regexp=^[a-zA-Z]*$"`),
    },
    {
        Name: "Age",
        Type: reflect.TypeOf(0), // int
        Tag:  reflect.StructTag(`validate:"min=6,max=100"`),
    },
})
打印此类型将由我包装输出,请在以下位置尝试:

创建此结构的实例后,可以使用函数对其进行验证,例如:

v := reflect.New(t)
v.Elem().FieldByName("Name").Set(reflect.ValueOf("Bob"))
v.Elem().FieldByName("Age").Set(reflect.ValueOf(12))

if errs := validator.Validate(v.Elem().Interface()); errs != nil {
    // values not valid, deal with errors here
}

我已经更新了我的答案。在上面的代码中,我将从前端获得动态JSON,如何转换为结构以将数据插入数据存储。虽然这是一个很好的解决方案,但我强烈反对使用它。这看起来像是一场噩梦,运行缓慢,最终很可能毫无意义。编译时结构或映射几乎肯定是更好的解决方案。@Adrian anysuggestion@Adrian是的,这正是我在第一段中的建议,剩下的就是回答这个问题。是的,只是第二次投票,真的,不要这样做,即使这是可能的!我已经更新了我的答案。在上面的代码中,我将从前端获得动态JSON,如何转换为结构以将数据插入数据存储。虽然这是一个很好的解决方案,但我强烈反对使用它。这看起来像是一场噩梦,运行缓慢,最终很可能毫无意义。编译时结构或映射几乎肯定是最好的
阿德里安·安尼suggestion@Adrian是的,这正是我在第一段中的建议,剩下的就是回答这个问题。是的,只是第二次投票,真的,不要这样做,即使这是可能的!
t := reflect.StructOf([]reflect.StructField{
    {
        Name: "Name",
        Type: reflect.TypeOf(""), // string
        Tag:  reflect.StructTag(`validate:"min=3,max=40,regexp=^[a-zA-Z]*$"`),
    },
    {
        Name: "Age",
        Type: reflect.TypeOf(0), // int
        Tag:  reflect.StructTag(`validate:"min=6,max=100"`),
    },
})
struct { Name string "validate:\"min=3,max=40,regexp=^[a-zA-Z]*$\"";
    Age int "validate:\"min=6,max=100\"" }
v := reflect.New(t)
v.Elem().FieldByName("Name").Set(reflect.ValueOf("Bob"))
v.Elem().FieldByName("Age").Set(reflect.ValueOf(12))

if errs := validator.Validate(v.Elem().Interface()); errs != nil {
    // values not valid, deal with errors here
}