我将struct传递给函数interface{}
。然后在内部使用它reflect
来获取struct属性。这是代码:
func (db *DB) Migrate(domain ...interface{}) {
// statement := "CREATE TABLE IF NOT EXISTS %s (%s, %s, %s, %s, %s)"
for _,i := range domain {
params := BindStruct(&i)
statement := CreateStatement("create", len(params))
_,err := db.Exec(fmt.Sprintf(statement, params...))
if err != nil {
log.Fatal("Error migrating database schema - ", err)
break
}
}
}
func BindStruct(domain interface{}) (params []interface{}) {
tableName := reflect.TypeOf(domain).Elem().Name()
params = append(params, tableName)
val := reflect.ValueOf(domain).Elem()
for i:=0; i < val.NumField(); i++ {
field := val.Type().Field(i)
tag := field.Tag
fieldName := field.Name
fieldType := tag.Get("sql_type")
fieldTags := tag.Get("sql_tag")
paramstring := fieldName + " " + fieldType + " " + fieldTags
params = append(params, paramstring)
}
return params
}
Run Code Online (Sandbox Code Playgroud)
我for i:=0; i < val.NumField(); i++ {
在BindStruct
函数行上出错。错误消息是:
紧急情况:反射:接口Value上对reflect.Value.NumField的调用
如果我删除&
从params := BindStruct(&i)
成为params := BindStruct(i)
在迁移功能,我得到这个错误:
紧急情况:运行时错误:无效的内存地址或nil指针
解引用[signal SIGSEGV:细分违规代码= 0x1 addr = 0x0 pc = 0x4ff457]
是什么赋予了?
调用时,BindStruct(&i)
您正在将指针传递给接口。所以这行:
val := reflect.ValueOf(domain).Elem()
Run Code Online (Sandbox Code Playgroud)
会将val设置为代表您的接口的reflect.Value,因为reflect.ValueOf(domain)
获取指针然后.Elem()
解析该接口-这导致您的第一个错误,因为它的确是接口值(并且它们没有字段):
紧急情况:反射:接口Value上对reflect.Value.NumField的调用
因此,调用params := BindStruct(i)
始终是正确的,因为您需要在不指向其的指针中传递实际接口。
您不清楚传入的底层数据类型是什么Migrate()
-它们是值还是指针?重要的是要知道,例如,使用反射来检查结构标签,我们需要回到结构值类型,因此该链为:
接口->(指针?)->值->类型
我怀疑您正在使用值,好像interface是一个值然后是该行:
val := reflect.ValueOf(domain).Elem()
Run Code Online (Sandbox Code Playgroud)
会恐慌,因为reflect.ValueOf(domain)
它将解析该值,然后.Elem()
尝试取消对某个值的引用。
为了安全起见,我们将检查传入值的Kind()以确保我们具有结构:
https://play.golang.org/p/6lPOwTd1Q0O
func BindStruct(domain interface{}) (params []interface{}) {
val := reflect.ValueOf(domain) // could be any underlying type
// if its a pointer, resolve its value
if val.Kind() == reflect.Ptr {
val = reflect.Indirect(val)
}
// should double check we now have a struct (could still be anything)
if val.Kind() != reflect.Struct {
log.Fatal("unexpected type")
}
// now we grab our values as before (note: I assume table name should come from the struct type)
structType := val.Type()
tableName := structType.Name()
params = append(params, tableName)
for i:=0; i < structType.NumField(); i++ {
field := structType.Field(i)
tag := field.Tag
fieldName := field.Name
fieldType := tag.Get("sql_type")
fieldTags := tag.Get("sql_tag")
paramstring := fieldName + " " + fieldType + " " + fieldTags
params = append(params, paramstring)
}
return params
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1740 次 |
最近记录: |