Skip to content

Instantly share code, notes, and snippets.

@dollarkillerx
Last active June 17, 2021 07:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dollarkillerx/6e9829a82ecfa55ef4fc31a98a9c1e9a to your computer and use it in GitHub Desktop.
Save dollarkillerx/6e9829a82ecfa55ef4fc31a98a9c1e9a to your computer and use it in GitHub Desktop.
golang反射
// BindEdgeAll(rr, &[]moe.r)
func BindEdgeAll(resultSet *nebula.ResultSet, v interface{}) error {
	refType := reflect.TypeOf(v)
	refVal := reflect.ValueOf(v)
	if refType.Kind() != reflect.Ptr {
		return errors.New("类型错误 应该为&[]")
	}

	// 解引用看内部类型
	if refType.Elem().Kind() != reflect.Slice {
		return errors.New("类型错误 应该为&[]")
	}

	elem := refType.Elem().Elem() // 内部具体的类型
	sliceVal := refVal.Elem()     // 具体slice

	// 建立一个新数组
	newArr := make([]reflect.Value, 0)

	// 建立一个item
	total := resultSet.GetRowSize()
	for i := 0; i < total; i++ {
		// Get a row from resultSet
		record, err := resultSet.GetRowValuesByIndex(i)
		if err != nil {
			return errors.WithStack(err)
		}

		edge, err := newEdge(record, elem)
		if err != nil {
			return errors.WithStack(err)
		}

		newArr = append(newArr, edge.Elem())
	}

	// 重写
	resArr := reflect.Append(sliceVal, newArr...)
	sliceVal.Set(resArr)

	return nil
}

// 无中生有
func newEdge(record *nebula.Record, elemType reflect.Type) (resVal reflect.Value, err error) {
	defer func() {
		if error := recover(); error != nil {
			err = errors.Errorf("%s", error)
		}
	}()
	// 1. 获取struct所有的 json tag
	// 2. 对应ColNames
	// 3. 类型转换
	// 4. 填数据
	refVal := reflect.New(elemType)
	refTypeElem := elemType
	refValElem := refVal.Elem()

	for i := 0; i < refTypeElem.NumField(); i++ {
		typeElem := refTypeElem.Field(i)
		structElem := refValElem.Field(i)
		if !structElem.CanSet() {
			continue
		}

		// 取tag
		tag := typeElem.Tag.Get("json")
		if tag == "" {
			tag = typeElem.Name
		}

		if tag == "-" {
			continue
		}

		col, err := record.GetValueByColName(tag)
		if err != nil {
			continue
		}

		switch typeElem.Type.Kind() {
		case reflect.Float64:
			f, err := col.AsFloat()
			if err != nil {
				continue
			}
			structElem.SetFloat(f)
		case reflect.String:
			s := strings.TrimSpace(col.String())
			s = strings.Replace(s, "\"", "", -1)
			structElem.SetString(s)
		}
	}

	return refVal, err
}

// BindEdge(c, &rs)
func BindEdge(record *nebula.Record, v interface{}) error {
	// 1. 获取struct所有的 json tag
	// 2. 对应ColNames
	// 3. 类型转换
	// 4. 填数据

	refType := reflect.TypeOf(v)
	refVal := reflect.ValueOf(v)
	if refType.Kind() != reflect.Ptr {
		return errors.New("应该传入指针")
	}

	refTypeElem := refType.Elem()
	refValElem := refVal.Elem()

	if refTypeElem.NumField() == 0 {
		return errors.New("模型绑定错误")
	}

	for i := 0; i < refTypeElem.NumField(); i++ {
		typeElem := refTypeElem.Field(i)
		structElem := refValElem.Field(i)
		if !structElem.CanSet() {
			continue
		}

		// 取tag
		tag := typeElem.Tag.Get("json")
		if tag == "" {
			tag = typeElem.Name
		}

		if tag == "-" {
			continue
		}

		col, err := record.GetValueByColName(tag)
		if err != nil {
			continue
		}

		switch typeElem.Type.Kind() {
		case reflect.Float64:
			f, err := col.AsFloat()
			if err != nil {
				continue
			}
			structElem.SetFloat(f)
		case reflect.String:
			s := strings.TrimSpace(col.String())
			s = strings.Replace(s, "\"", "", -1)
			structElem.SetString(s)
		}
	}

	return nil
}

反射创建一个新的对象

refType := reflect.TypeOf(MockModel{})
after = reflect.New(refType).Interface()  // 这是一个指针

穷尽获取struct里面所有的元素类型

func GetModelFields(v reflect.Value) []reflect.StructField {
	sf := make([]reflect.StructField, 0)
	if v.Type().Kind() != reflect.Struct {
		panic("CDC Connector Deserialization Please pass in the structure !!!!")
	}

	for i := 0; i < v.NumField(); i++ {
		field := v.Type().Field(i)
		if field.Type.Kind() == reflect.Struct && IsInnerStruct(field) {
			innerSF := GetModelFields(v.Field(i))
			sf = append(sf, innerSF...)
		} else {
			sf = append(sf, field)
		}
	}
	return sf
}

直接进行值赋值

switch value.Type().Kind() {
		default:  // 普通元素
			beforeElem.FieldByName(fieldName).Set(oldBeforeElem.FieldByName(fieldName))
		case reflect.Ptr: // 针对指针
			beforeElem.FieldByName(fieldName).Set(reflect.New(oldBeforeElem.FieldByName(fieldName).Type().Elem()))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment