Maison  >  Article  >  développement back-end  >  Comment implémenter la copie profonde dans Golang

Comment implémenter la copie profonde dans Golang

PHPz
PHPzoriginal
2023-04-24 14:46:184136parcourir

En langage Go (golang), on a souvent besoin de copier des structures ou des objets. L'affectation directe ou la copie superficielle peuvent provoquer des erreurs difficiles à déboguer. Par conséquent, la copie approfondie est très nécessaire. Cet article présentera comment Golang implémente la copie approfondie.

Le concept de copie profonde

La copie profonde consiste à créer une nouvelle copie de toutes les propriétés internes d'un objet. De cette façon, même si un certain attribut est modifié dans l’objet original et dans la copie, cela ne s’affectera pas. La copie superficielle copie uniquement les pointeurs et plusieurs objets pointent vers la même adresse. La modification des propriétés d'un objet affectera d'autres objets.

Méthode de copie approfondie dans Golang

Méthode 1 : utilisez json.Marshal() et json.Unmarshal()

Cette méthode est relativement simple, vous pouvez utiliser json.Marshal() et json.Unmarshal() dans la bibliothèque standard fonction.

Par exemple :

type Person struct {
    Name string
    Age int
}

person1 := &Person{"Lucas", 18}
var person2 Person

temp, _ := json.Marshal(person1) //使用json.Marshal()将person1转换成json格式
json.Unmarshal(temp, &person2) //使用json.Unmarshal()将json格式转换成person2实例

Cependant, cette méthode présente certains inconvénients. Tout d'abord, vous devez vous assurer que le format json converti n'a pas le même json que le champ, sinon le json ne pourra pas être reconverti en structure. Deuxièmement, json.Marshal() et json.Unmarshal() doivent parcourir l'intégralité de l'objet, ce qui entraîne une vitesse plus lente. Par conséquent, il ne peut pas être utilisé pour des structures de données complexes et des applications nécessitant des performances efficaces.

Méthode 2 : Utiliser la méthode récursive

La copie profonde récursive est la méthode la plus couramment utilisée. Parcourez chaque élément de l'objet ou du tableau, copiez-le directement s'il s'agit d'un type de base, ou appelez la fonction de copie approfondie de manière récursive s'il s'agit d'un type complexe. Le code est le suivant :

func DeepCopy(input interface{}) interface{} {
    if input == nil {
        return nil
    }

    switch reflect.TypeOf(input).Kind() {

    case reflect.Bool, reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float32, reflect.Float64:
        return input

    case reflect.Struct:
        in := reflect.ValueOf(input)
        out := reflect.New(in.Type()).Elem()

        for i := 0; i < in.NumField(); i++ {
            out.Field(i).Set(DeepCopy(in.Field(i).Interface()))
        }
        return out.Interface()

    case reflect.Array, reflect.Slice:
        in := reflect.ValueOf(input)
        out := reflect.MakeSlice(in.Type(), in.Len(), in.Cap())

        for i := 0; i < in.Len(); i++ {
            out.Index(i).Set(DeepCopy(in.Index(i).Interface()))
        }
        return out.Interface()

    case reflect.Map:
        in := reflect.ValueOf(input)
        out := reflect.MakeMapWithSize(in.Type(), in.Len())

        for _, key := range in.MapKeys() {
            out.SetMapIndex(DeepCopy(key.Interface()).(reflect.Value), DeepCopy(in.MapIndex(key).Interface()).(reflect.Value))
        }
        return out.Interface()

    default:
        panic(fmt.Sprintf("Unable to deepcopy object of type %v", reflect.TypeOf(input)))
    }
}

Dans ce code, nous utilisons d'abord Reflect.TypeOf() pour obtenir le type d'objet, puis appelons différentes fonctions de copie profonde en fonction de la définition du type.

Nous pouvons tester les types courants :

type Person struct {
    Name string
    Age int
}

type Object struct {
    Num int
    Str string
    Slice []int
    Map map[string]int
    Person Person
}

func main() {

    obj1 := &Object{1, "hello", []int{2, 3}, map[string]int{"age": 18}, Person{"Lucas", 20}}

    //深拷贝
    obj2 := DeepCopy(obj1)

    //修改obj1的Name字段
    obj1.Person.Name = "Nina"

    fmt.Println("obj1:", obj1)
    fmt.Println("obj2:", obj2)
}

Les résultats de sortie sont les suivants :

obj1: &{1 hello [2 3] map[age:18] {Nina 20}}
obj2: &{1 hello [2 3] map[age:18] {Lucas 20}}

On peut voir que les valeurs​​de obj1 et obj2 sont différentes, et la modification de la valeur de obj1 n'affectera pas obj2.

Résumé

Cet article présente deux méthodes de copie profonde dans Golang. Pour les structures simples, vous pouvez utiliser json.Marshal() et json.Unmarshal(). Pour les structures de données complexes, des méthodes récursives peuvent être utilisées pour la copie approfondie. Lorsque vous effectuez une copie approfondie, vous devez faire attention au jugement du type de données pour éviter des erreurs inutiles.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn