关于结构体复制问题

有两个结构体:

type A struct {
    ID int
    Name string
}

type B struct {
    ID int
    Name string
}

结构体类型不同,但是结构体内参数完全一致,可以相互复制吗?例如 A.ID = 1,A.Name = “abc”,怎么把整个结构体的内容复制给B结构体?不要跟我说一个参数一个参数去=….

共 5 个回复


stevewang

用unsafe可以做到,但是很不安全,强烈不推荐:

    type A struct {
        ID   int
        Name string
    }
    type B struct {
        ID   int
        Name string
    }
    var a = A{
        ID: 1,
        Name: "Instance of A",
    }
    var b B = *(*B)(unsafe.Pointer(&a))

如果挨个成员赋值嫌麻烦,可以封装成一个函数就方便了:

func BuildBFromA(a *A) B {
    return B{
        ID:   a.ID,
        Name: a.Name,
    }
}
# 0

sryan

不能直接复制
可以使用反射来赋值

type A struct {
    ID   int
    Name string
}

type B struct {
    ID   int
    Name string
}

func CopyStruct(src interface{}, dest interface{}) error {
    vsrc := reflect.ValueOf(src)
    vdest := reflect.ValueOf(dest)

    if vsrc.Kind() != reflect.Ptr ||
        vdest.Kind() != reflect.Ptr {
        return fmt.Errorf("Invalid input")
    }

    esrc := vsrc.Elem()
    edest := vdest.Elem()

    if esrc.Kind() != reflect.Struct ||
        esrc.Kind() != reflect.Struct {
        return fmt.Errorf("Invalid input")
    }

    tsrc := esrc.Type()
    for i := 0; i < esrc.NumField(); i++ {
        sourceField := esrc.Field(i)
        sourceFieldName := tsrc.Field(i).Name
        destFiled := edest.FieldByName(sourceFieldName)

        if !destFiled.IsValid() {
            continue
        }
        if destFiled.Kind() != sourceField.Kind() {
            continue
        }

        switch sourceField.Kind() {
        //    int...
        case reflect.Int:
            fallthrough
        case reflect.Int8:
            fallthrough
        case reflect.Int16:
            fallthrough
        case reflect.Int32:
            fallthrough
        case reflect.Int64:
            {
                destFiled.SetInt(sourceField.Int())
            }
        // uint...
        case reflect.Uint:
            fallthrough
        case reflect.Uint8:
            fallthrough
        case reflect.Uint16:
            fallthrough
        case reflect.Uint32:
            fallthrough
        case reflect.Uint64:
            {
                destFiled.SetUint(sourceField.Uint())
            }
        // string
        case reflect.String:
            {
                destFiled.SetString(sourceField.String())
            }
        }
    }

    return nil
}

func main() {
    a := &A{
        ID:   1,
        Name: "hehe",
    }
    b := &B{}

    CopyStruct(a, b)
    log.Println(b)
}
# 1

Simbory

将A struct 序列化成json 然后再将json反序列化成B struct

# 2

yuankan20081

花点时间改下你类型的定义呗
对于类型B的使用又不会影响

# 4