add: some user api and all api desc
This commit is contained in:
@@ -40,7 +40,7 @@ func StructToStruct(src, dst interface{}) error
|
||||
```go
|
||||
import "app/common/converter"
|
||||
|
||||
// 单个 model 转 pb
|
||||
// 单个 models 转 pb
|
||||
user, _ := m.FindOne(ctx, userId)
|
||||
pbUser := &pb.Users{}
|
||||
converter.StructToStruct(user, pbUser)
|
||||
@@ -63,7 +63,7 @@ func SliceToSlice(src interface{}, dstSliceType interface{}) (interface{}, error
|
||||
**示例:**
|
||||
|
||||
```go
|
||||
// 多个 model 转 pb
|
||||
// 多个 models 转 pb
|
||||
users := []*models.Users{user1, user2, user3}
|
||||
pbUsersIface, _ := converter.SliceToSlice(users, []*pb.Users{})
|
||||
pbUsers := pbUsersIface.([]*pb.Users)
|
||||
|
||||
+207
-207
@@ -1,207 +1,207 @@
|
||||
package converter
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// StructToStruct 通用结构体转换函数,利用反射将源结构体的字段值复制到目标结构体
|
||||
// src: 源结构体(通常是 model)
|
||||
// dst: 目标结构体(通常是 pb),必须是指针
|
||||
// 支持的自动转换:
|
||||
// - time.Time -> int64 (Unix 时间戳)
|
||||
// - sql.NullTime -> int64 (如果有效)
|
||||
// - sql.NullInt64 -> int64
|
||||
// - sql.NullString -> string
|
||||
// - 相同名称和兼容类型的字段
|
||||
func StructToStruct(src, dst interface{}) error {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
srcVal := reflect.ValueOf(src)
|
||||
dstVal := reflect.ValueOf(dst)
|
||||
|
||||
// 确保 dst 是指针
|
||||
if dstVal.Kind() != reflect.Ptr {
|
||||
return newError("destination must be a pointer")
|
||||
}
|
||||
|
||||
dstVal = dstVal.Elem()
|
||||
|
||||
// 如果 src 是指针,解引用
|
||||
if srcVal.Kind() == reflect.Ptr {
|
||||
srcVal = srcVal.Elem()
|
||||
}
|
||||
|
||||
// 都必须是结构体
|
||||
if srcVal.Kind() != reflect.Struct || dstVal.Kind() != reflect.Struct {
|
||||
return newError("both source and destination must be structs")
|
||||
}
|
||||
|
||||
srcType := srcVal.Type()
|
||||
|
||||
// 遍历源结构体的所有字段
|
||||
for i := 0; i < srcVal.NumField(); i++ {
|
||||
srcField := srcVal.Field(i)
|
||||
srcFieldName := srcType.Field(i).Name
|
||||
|
||||
// 在目标结构体中查找同名字段
|
||||
dstField := dstVal.FieldByName(srcFieldName)
|
||||
if !dstField.IsValid() || !dstField.CanSet() {
|
||||
continue
|
||||
}
|
||||
|
||||
// 进行类型转换和赋值
|
||||
if err := assignValue(srcField, dstField); err != nil {
|
||||
continue // 如果单个字段转换失败,继续处理其他字段
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// assignValue 尝试将源字段值赋给目标字段
|
||||
func assignValue(srcField, dstField reflect.Value) error {
|
||||
// 如果是可直接赋值的类型
|
||||
if srcField.Type() == dstField.Type() {
|
||||
dstField.Set(srcField)
|
||||
return nil
|
||||
}
|
||||
|
||||
srcType := srcField.Type()
|
||||
dstType := dstField.Type()
|
||||
|
||||
// 处理 time.Time -> int64 的转换
|
||||
if srcType == reflect.TypeOf(time.Time{}) && dstType.Kind() == reflect.Int64 {
|
||||
t := srcField.Interface().(time.Time)
|
||||
dstField.SetInt(t.Unix())
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理 sql.NullTime -> int64 的转换
|
||||
if srcType == reflect.TypeOf(sql.NullTime{}) && dstType.Kind() == reflect.Int64 {
|
||||
nt := srcField.Interface().(sql.NullTime)
|
||||
if nt.Valid {
|
||||
dstField.SetInt(nt.Time.Unix())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理 sql.NullTime -> time.Time 的转换
|
||||
if srcType == reflect.TypeOf(sql.NullTime{}) && dstType == reflect.TypeOf(time.Time{}) {
|
||||
nt := srcField.Interface().(sql.NullTime)
|
||||
if nt.Valid {
|
||||
dstField.Set(reflect.ValueOf(nt.Time))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理 sql.NullInt64 -> int64 的转换
|
||||
if srcType == reflect.TypeOf(sql.NullInt64{}) && dstType.Kind() == reflect.Int64 {
|
||||
ni := srcField.Interface().(sql.NullInt64)
|
||||
if ni.Valid {
|
||||
dstField.SetInt(ni.Int64)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理 sql.NullString -> string 的转换
|
||||
if srcType == reflect.TypeOf(sql.NullString{}) && dstType.Kind() == reflect.String {
|
||||
ns := srcField.Interface().(sql.NullString)
|
||||
if ns.Valid {
|
||||
dstField.SetString(ns.String)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理 sql.NullBool -> bool 的转换
|
||||
if srcType == reflect.TypeOf(sql.NullBool{}) && dstType.Kind() == reflect.Bool {
|
||||
nb := srcField.Interface().(sql.NullBool)
|
||||
if nb.Valid {
|
||||
dstField.SetBool(nb.Bool)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理 int -> int64 的转换
|
||||
if srcType.Kind() == reflect.Int && dstType.Kind() == reflect.Int64 {
|
||||
dstField.SetInt(int64(srcField.Int()))
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理 int64 -> int 的转换
|
||||
if srcType.Kind() == reflect.Int64 && dstType.Kind() == reflect.Int {
|
||||
dstField.SetInt(srcField.Int())
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理 string -> string(某些情况下可能存在复制)
|
||||
if srcType.Kind() == reflect.String && dstType.Kind() == reflect.String {
|
||||
dstField.SetString(srcField.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理 bool -> bool
|
||||
if srcType.Kind() == reflect.Bool && dstType.Kind() == reflect.Bool {
|
||||
dstField.SetBool(srcField.Bool())
|
||||
return nil
|
||||
}
|
||||
|
||||
return newError("unsupported type conversion from " + srcType.String() + " to " + dstType.String())
|
||||
}
|
||||
|
||||
// SliceToSlice 通用切片转换函数,使用 StructToStruct 转换每个元素
|
||||
func SliceToSlice(src interface{}, dstSliceType interface{}) (interface{}, error) {
|
||||
srcVal := reflect.ValueOf(src)
|
||||
|
||||
// src 必须是切片
|
||||
if srcVal.Kind() != reflect.Slice {
|
||||
return nil, newError("source must be a slice")
|
||||
}
|
||||
|
||||
// 获取原始 dst slice type
|
||||
dstSliceVal := reflect.ValueOf(dstSliceType)
|
||||
if dstSliceVal.Kind() != reflect.Slice {
|
||||
return nil, newError("dstSliceType must be a slice type")
|
||||
}
|
||||
|
||||
dstSliceElemType := dstSliceVal.Type().Elem()
|
||||
|
||||
// 创建新的目标切片
|
||||
dstSlice := reflect.MakeSlice(dstSliceVal.Type(), srcVal.Len(), srcVal.Len())
|
||||
|
||||
// 逐个转换元素
|
||||
for i := 0; i < srcVal.Len(); i++ {
|
||||
srcElem := srcVal.Index(i)
|
||||
dstElem := reflect.New(dstSliceElemType)
|
||||
|
||||
// 如果 src 元素是指针,需要解引用
|
||||
if srcElem.Kind() == reflect.Ptr {
|
||||
srcElem = srcElem.Elem()
|
||||
}
|
||||
|
||||
// 转换单个元素
|
||||
dstElemIface := dstElem.Interface()
|
||||
if err := StructToStruct(srcElem.Interface(), dstElemIface); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dstSlice.Index(i).Set(dstElem.Elem())
|
||||
}
|
||||
|
||||
return dstSlice.Interface(), nil
|
||||
}
|
||||
|
||||
type Error struct {
|
||||
msg string
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
return e.msg
|
||||
}
|
||||
|
||||
func newError(msg string) error {
|
||||
return &Error{msg: msg}
|
||||
}
|
||||
package converter
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// StructToStruct 通用结构体转换函数,利用反射将源结构体的字段值复制到目标结构体
|
||||
// src: 源结构体(通常是 models)
|
||||
// dst: 目标结构体(通常是 pb),必须是指针
|
||||
// 支持的自动转换:
|
||||
// - time.Time -> int64 (Unix 时间戳)
|
||||
// - sql.NullTime -> int64 (如果有效)
|
||||
// - sql.NullInt64 -> int64
|
||||
// - sql.NullString -> string
|
||||
// - 相同名称和兼容类型的字段
|
||||
func StructToStruct(src, dst interface{}) error {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
srcVal := reflect.ValueOf(src)
|
||||
dstVal := reflect.ValueOf(dst)
|
||||
|
||||
// 确保 dst 是指针
|
||||
if dstVal.Kind() != reflect.Ptr {
|
||||
return newError("destination must be a pointer")
|
||||
}
|
||||
|
||||
dstVal = dstVal.Elem()
|
||||
|
||||
// 如果 src 是指针,解引用
|
||||
if srcVal.Kind() == reflect.Ptr {
|
||||
srcVal = srcVal.Elem()
|
||||
}
|
||||
|
||||
// 都必须是结构体
|
||||
if srcVal.Kind() != reflect.Struct || dstVal.Kind() != reflect.Struct {
|
||||
return newError("both source and destination must be structs")
|
||||
}
|
||||
|
||||
srcType := srcVal.Type()
|
||||
|
||||
// 遍历源结构体的所有字段
|
||||
for i := 0; i < srcVal.NumField(); i++ {
|
||||
srcField := srcVal.Field(i)
|
||||
srcFieldName := srcType.Field(i).Name
|
||||
|
||||
// 在目标结构体中查找同名字段
|
||||
dstField := dstVal.FieldByName(srcFieldName)
|
||||
if !dstField.IsValid() || !dstField.CanSet() {
|
||||
continue
|
||||
}
|
||||
|
||||
// 进行类型转换和赋值
|
||||
if err := assignValue(srcField, dstField); err != nil {
|
||||
continue // 如果单个字段转换失败,继续处理其他字段
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// assignValue 尝试将源字段值赋给目标字段
|
||||
func assignValue(srcField, dstField reflect.Value) error {
|
||||
// 如果是可直接赋值的类型
|
||||
if srcField.Type() == dstField.Type() {
|
||||
dstField.Set(srcField)
|
||||
return nil
|
||||
}
|
||||
|
||||
srcType := srcField.Type()
|
||||
dstType := dstField.Type()
|
||||
|
||||
// 处理 time.Time -> int64 的转换
|
||||
if srcType == reflect.TypeOf(time.Time{}) && dstType.Kind() == reflect.Int64 {
|
||||
t := srcField.Interface().(time.Time)
|
||||
dstField.SetInt(t.Unix())
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理 sql.NullTime -> int64 的转换
|
||||
if srcType == reflect.TypeOf(sql.NullTime{}) && dstType.Kind() == reflect.Int64 {
|
||||
nt := srcField.Interface().(sql.NullTime)
|
||||
if nt.Valid {
|
||||
dstField.SetInt(nt.Time.Unix())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理 sql.NullTime -> time.Time 的转换
|
||||
if srcType == reflect.TypeOf(sql.NullTime{}) && dstType == reflect.TypeOf(time.Time{}) {
|
||||
nt := srcField.Interface().(sql.NullTime)
|
||||
if nt.Valid {
|
||||
dstField.Set(reflect.ValueOf(nt.Time))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理 sql.NullInt64 -> int64 的转换
|
||||
if srcType == reflect.TypeOf(sql.NullInt64{}) && dstType.Kind() == reflect.Int64 {
|
||||
ni := srcField.Interface().(sql.NullInt64)
|
||||
if ni.Valid {
|
||||
dstField.SetInt(ni.Int64)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理 sql.NullString -> string 的转换
|
||||
if srcType == reflect.TypeOf(sql.NullString{}) && dstType.Kind() == reflect.String {
|
||||
ns := srcField.Interface().(sql.NullString)
|
||||
if ns.Valid {
|
||||
dstField.SetString(ns.String)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理 sql.NullBool -> bool 的转换
|
||||
if srcType == reflect.TypeOf(sql.NullBool{}) && dstType.Kind() == reflect.Bool {
|
||||
nb := srcField.Interface().(sql.NullBool)
|
||||
if nb.Valid {
|
||||
dstField.SetBool(nb.Bool)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理 int -> int64 的转换
|
||||
if srcType.Kind() == reflect.Int && dstType.Kind() == reflect.Int64 {
|
||||
dstField.SetInt(int64(srcField.Int()))
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理 int64 -> int 的转换
|
||||
if srcType.Kind() == reflect.Int64 && dstType.Kind() == reflect.Int {
|
||||
dstField.SetInt(srcField.Int())
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理 string -> string(某些情况下可能存在复制)
|
||||
if srcType.Kind() == reflect.String && dstType.Kind() == reflect.String {
|
||||
dstField.SetString(srcField.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理 bool -> bool
|
||||
if srcType.Kind() == reflect.Bool && dstType.Kind() == reflect.Bool {
|
||||
dstField.SetBool(srcField.Bool())
|
||||
return nil
|
||||
}
|
||||
|
||||
return newError("unsupported type conversion from " + srcType.String() + " to " + dstType.String())
|
||||
}
|
||||
|
||||
// SliceToSlice 通用切片转换函数,使用 StructToStruct 转换每个元素
|
||||
func SliceToSlice(src interface{}, dstSliceType interface{}) (interface{}, error) {
|
||||
srcVal := reflect.ValueOf(src)
|
||||
|
||||
// src 必须是切片
|
||||
if srcVal.Kind() != reflect.Slice {
|
||||
return nil, newError("source must be a slice")
|
||||
}
|
||||
|
||||
// 获取原始 dst slice type
|
||||
dstSliceVal := reflect.ValueOf(dstSliceType)
|
||||
if dstSliceVal.Kind() != reflect.Slice {
|
||||
return nil, newError("dstSliceType must be a slice type")
|
||||
}
|
||||
|
||||
dstSliceElemType := dstSliceVal.Type().Elem()
|
||||
|
||||
// 创建新的目标切片
|
||||
dstSlice := reflect.MakeSlice(dstSliceVal.Type(), srcVal.Len(), srcVal.Len())
|
||||
|
||||
// 逐个转换元素
|
||||
for i := 0; i < srcVal.Len(); i++ {
|
||||
srcElem := srcVal.Index(i)
|
||||
dstElem := reflect.New(dstSliceElemType)
|
||||
|
||||
// 如果 src 元素是指针,需要解引用
|
||||
if srcElem.Kind() == reflect.Ptr {
|
||||
srcElem = srcElem.Elem()
|
||||
}
|
||||
|
||||
// 转换单个元素
|
||||
dstElemIface := dstElem.Interface()
|
||||
if err := StructToStruct(srcElem.Interface(), dstElemIface); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dstSlice.Index(i).Set(dstElem.Elem())
|
||||
}
|
||||
|
||||
return dstSlice.Interface(), nil
|
||||
}
|
||||
|
||||
type Error struct {
|
||||
msg string
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
return e.msg
|
||||
}
|
||||
|
||||
func newError(msg string) error {
|
||||
return &Error{msg: msg}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user