interface <-> type
郭學聰 Hsueh-Tsung KuoThu, 26 Jun 2018
typ := reflect.TypeOf(v) kind := typ.Kind() elemTyp := typ.Elem() // ptr or slice fieldCount := typ.NumField() fieldInfo := typ.Field(i)
type Kind uint const ( Invalid Kind = iota Bool Int Int8 Int16 Int32 Int64 Uint Uint8 Uint16 Uint32 Uint64 Uintptr Float32 Float64 Complex64 Complex128 Array Chan Func Interface Map Ptr Slice String Struct UnsafePointer )
// A StructField describes a single field in a struct. type StructField struct { // Name is the field name. Name string // PkgPath is the package path that qualifies a lower case (unexported) // field name. It is empty for upper case (exported) field names. // See https://golang.org/ref/spec#Uniqueness_of_identifiers PkgPath string Type Type // field type Tag StructTag // field tag string Offset uintptr // offset within struct, in bytes Index []int // index sequence for Type.FieldByIndex Anonymous bool // is an embedded field }
// tag = `json:"fieldName,...,inline,..." bson:"fieldName,..."` tagValue := tag.Get("json") // "fieldName,...,inline,..." // |-- options --|
package main import ( "fmt" "reflect" ) type ApiError struct { } func (e *ApiError) Error() string { return "api-error" } func Process() *ApiError { return nil } func main() { err := Process() fmt.Println(err == nil) fmt.Println(reflect.TypeOf(err)) fmt.Println(err) }
true
*main.ApiError
api-error
package main import ( "fmt" "reflect" ) type ApiError struct { } func (e *ApiError) Error() string { return "api-error" } func Process() *ApiError { return nil } func main() { var err error err = Process() fmt.Println(err == nil) fmt.Println(reflect.TypeOf(err)) fmt.Println(err) }
false
*main.ApiError
api-error
package main import ( "fmt" "reflect" ) type ApiError struct { } func (e *ApiError) Error() string { return "api-error" } func Process() *ApiError { return nil } func main() { var err error fmt.Println(err == nil) fmt.Println(reflect.TypeOf(err)) fmt.Println(err) err = Process() fmt.Println(err == nil) fmt.Println(err == (*ApiError)(nil)) fmt.Println(reflect.TypeOf(err)) fmt.Println(err) }
true
<nil>
<nil>
false
true
*main.ApiError
api-error
type Doc struct { Data1 string `json:"data1" bson:"data1"` Data2 int `json:"data2" bson:"data2"` } err := mongoCollection.Find(bson.M{ "name": name, }).Select(bson.M{ "data1": data1, "data2": data2, }).One(&doc)
type Doc struct { Data1 string `json:"data1" bson:"data1"` Data2 int `json:"data2" bson:"data2"` } err := mongoCollection.Find(bson.M{ "name": name, }).Select(ExtractFieldName(doc)).One(&doc)
package util import ( "reflect" "strings" ) type FieldMap map[string]interface{} func ExtractFieldName(tagKey string, v interface{}) FieldMap { m := FieldMap{} typ := reflect.TypeOf(v) for typ.Kind() == reflect.Ptr || typ.Kind() == reflect.Slice { typ = typ.Elem() } for i := 0; i < typ.NumField(); i++ { tagValue := typ.Field(i).Tag.Get(tagKey) fieldName := strings.Split(tagValue, ",")[0] if fieldName != "" { m[fieldName] = 1 } } return m }
type Doc struct { *Doc2 `json:",inline" bson:",inline"` *Doc3 `json:",inline" bson:",inline"` Data1 string `json:"data1" bson:"data1"` Data2 int `json:"data2" bson:"data2"` } type Doc2 struct { Data3 string `json:"data3" bson:"data3"` Data4 int `json:"data4" bson:"data4"` } type Doc3 struct { Data5 string `json:"data5" bson:"data5"` Data6 int `json:"data6" bson:"data6"` *Doc4 `json:",inline" bson:",inline"` } type Doc4 struct { Data7 string `json:"data7" bson:"data7"` Data8 int `json:"data8" bson:"data8"` }
package util import ( "reflect" "strings" ) type FieldMap map[string]interface{} func ExtractFieldName(tagKey string, v interface{}) FieldMap { m := FieldMap{} typ := reflect.TypeOf(v) extractFieldNameOfOneDepth(tagKey, typ, m) return m } func extractFieldNameOfOneDepth(tagKey string, typ reflect.Type, m FieldMap) { for typ.Kind() == reflect.Ptr || typ.Kind() == reflect.Slice { typ = typ.Elem() } for i := 0; i < typ.NumField(); i++ { fieldInfo := typ.Field(i) tagValue := fieldInfo.Tag.Get(tagKey) tagElements := strings.Split(tagValue, ",") for _, tagOption := range tagElements[1:] { if tagOption == "inline" { extractFieldNameOfOneDepth(tagKey, fieldInfo.Type, m) } } fieldName := tagElements[0] if fieldName != "" { m[fieldName] = 1 } } }
"blue reflection"
Hsueh-Tsung KuoThu, 26 Apr 2018