Nag*_* SV 1 reflection struct types go
Go中可以通过编程方式创建结构类型(即不在编译的源代码中)吗?
我们有一个特殊的用例,其中将通过用户定义的元数据创建类型(因此事先不知道模式/类型),并且每个客户都会有所不同。然后,我们需要为这些服务自动生成REST服务,并将其保留在NoSQL后端中。我们还需要为每个字段定义不同的动态验证器(例如,必填项,正则表达式,最大/最小大小,最大/最小值,对另一个类型实例的引用等)。
我想知道在Go中是否可以进行类似的操作?
编辑1:
例如
从JSON中的前端
For customer 1:
{
"id":1,
"patientid":1,
"name":"test1",
"height":"160",
"weight":"70",
"temp":"98"
}
For customer 2:
{
"id":2,
"patientid":1,
"name":"test1",
"height":"160",
"weight":"70"
}
For customer 3
may be different new fields will add
Run Code Online (Sandbox Code Playgroud)
后端
// For One customer need to have these fields
type Vitalsigns struct {
ID int64 `datastore:"-"`
PatientID int64 `json:"patientid,omitempty"`
Name string `json:"name,omitempty"`
Height string `json:"height,omitempty"`
Weight string `json:"weight,omitempty"`
Temp string `json:"temp,omitempty"`
}
// Another need to have these fields
type Vitalsigns struct {
ID int64 `datastore:"-"`
PatientID int64 `json:"patientid,omitempty"`
Name string `json:"name,omitempty"`
Height string `json:"height,omitempty"`
Weight string `json:"weight,omitempty"`
}
//CreateVitalsignsHandler is to create vitals for a patient
func CreateVitalsignsHandler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
//Creating the Vitalsigns
kinVitalsigns := &Vitalsigns{}
ctx := appengine.NewContext(r)
if err := json.NewDecoder(r.Body).Decode(kinVitalsigns); err != nil {
RespondErr(w, r, http.StatusInternalServerError, err.Error())
return
}
//Getting namespace
namespace := ps.ByName("namespace")
ctx, err := appengine.Namespace(ctx, namespace)
if err != nil {
log.Infof(ctx, "Namespace error from CreateVitalsignsHandler")
RespondErr(w, r, http.StatusInternalServerError, err.Error())
return
}
//Geting the patientID
pID, err := strconv.Atoi(ps.ByName("id"))
if err != nil {
log.Infof(ctx, "Srting to Int64 conversion error from CreateVitalsignsHandler")
RespondErr(w, r, http.StatusInternalServerError, err.Error())
return
}
patientID := int64(pID)
kinVitalsigns.PatientID = patientID
//Generating the key
vitalsignsKey := datastore.NewIncompleteKey(ctx, "Vitalsigns", nil)
//Inserting the data to the datastore
vk, err := datastore.Put(ctx, vitalsignsKey, kinVitalsigns)
if err != nil {
log.Infof(ctx, "Entity creation was failed from CreateVitalsignsHandler")
RespondErr(w, r, http.StatusInternalServerError, err.Error())
return
}
kinVitalsigns.ID = vk.IntID()
message := "Vitalsigns created successfully!! "
Respond(w, r, http.StatusOK, SuccessResponse{kinVitalsigns.ID, 0, "", message})
return
}
Run Code Online (Sandbox Code Playgroud)
编辑:您的编辑显示您想处理要放置/从Google数据存储中检索的动态对象。为此,完全不需要在运行时创建结构类型,您可以只使用此答案中提供的动态映射:如何在Google App Engine数据存储区中使用动态属性。
原始答案如下。
请注意,如果类型在编译时是已知的,那么最好/最有效的方法就是创建类型并进行编译,因此所有内容都是“静态的”。您可以手动创建类型,也可以用于go generate自动执行该过程。
还要注意,您不一定需要使用结构类型来为动态对象建模,很多时候映射可能就足够了。
如果类型在编译时未知,并且必须是struct类型,请继续阅读。
是的,可以在运行时使用Go的反射(特别是使用该reflect.StructOf()函数)创建“动态”结构类型。
让我们看一个简单的示例,在运行时创建一个具有Name string和Age int字段的结构类型:
t := reflect.StructOf([]reflect.StructField{
{
Name: "Name",
Type: reflect.TypeOf(""), // string
},
{
Name: "Age",
Type: reflect.TypeOf(0), // int
},
})
fmt.Println(t)
v := reflect.New(t)
fmt.Printf("%+v\n", v)
v.Elem().FieldByName("Name").Set(reflect.ValueOf("Bob"))
v.Elem().FieldByName("Age").Set(reflect.ValueOf(12))
fmt.Printf("%+v\n", v)
Run Code Online (Sandbox Code Playgroud)
输出(在Go Playground上尝试):
struct { Name string; Age int }
&{Name: Age:0}
&{Name:Bob Age:12}
Run Code Online (Sandbox Code Playgroud)
如果要定义验证规则,则可以为此使用第三方库github.com/go-validator/validator。该软件包使用struct标签来指定验证规则,也可以使用反射来指定struct标签。
例如,如果你想指定的Name必须至少为3个字符和40最多,它可能只包含英文字母的字符,并且有效范围Age是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"`),
},
})
Run Code Online (Sandbox Code Playgroud)
打印此类型将输出(由我包装)(在Go Playground上尝试):
struct { Name string "validate:\"min=3,max=40,regexp=^[a-zA-Z]*$\"";
Age int "validate:\"min=6,max=100\"" }
Run Code Online (Sandbox Code Playgroud)
一旦创建了该结构的实例,就可以使用validator.Validate()函数来验证它,例如:
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
}
Run Code Online (Sandbox Code Playgroud)