github.com/searKing/golang/go@v1.2.74/util/object/clone.go (about)

     1  // Copyright 2020 The searKing Author. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package object
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/gob"
    10  	"reflect"
    11  )
    12  
    13  // DeepCopys returns a interface consisting of the deeply copying elements.
    14  // just clone public&clonable elems - upper case - name & IsCloneable()==true
    15  func DeepClone(obj interface{}) (copy interface{}) {
    16  	if !IsNilable(obj) || !IsCloneable(obj) {
    17  		return obj
    18  	}
    19  	v := reflect.ValueOf(obj)
    20  	copyV := reflect.New(v.Type()).Elem()
    21  	deepClones(obj, copyV.Addr().Interface())
    22  	return copyV.Interface()
    23  }
    24  
    25  // deepClones provides the method to creates a deep copy of whatever is passed to
    26  // it and returns the copy in an interface. The returned value will need to be
    27  // asserted to the correct type.
    28  func deepClones(origin, copy interface{}) error {
    29  	var buf bytes.Buffer
    30  	if err := gob.NewEncoder(&buf).Encode(origin); err != nil {
    31  		return err
    32  	}
    33  	return gob.NewDecoder(bytes.NewBuffer(buf.Bytes())).Decode(copy)
    34  }
    35  
    36  // IsCloneable Returns {@code true} if the arguments are a chan or func field
    37  // or pointer to chan or func
    38  // and {@code false} otherwise.
    39  func IsCloneable(obj interface{}) bool {
    40  	switch t := reflect.ValueOf(obj); t.Kind() {
    41  	// All basic types are easy: they are predefined.
    42  	case reflect.Bool:
    43  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    44  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
    45  	case reflect.Float32, reflect.Float64:
    46  	case reflect.Complex64, reflect.Complex128:
    47  	case reflect.String:
    48  	case reflect.Interface:
    49  	case reflect.Array:
    50  	case reflect.Map:
    51  	case reflect.Slice:
    52  	case reflect.Struct:
    53  	default:
    54  		// If the field is a chan or func or pointer thereto, don't send it.
    55  		// That is, treat it like an unexported field.
    56  		for t.Kind() == reflect.Ptr {
    57  			t = t.Elem()
    58  		}
    59  		if t.Kind() == reflect.Chan || t.Kind() == reflect.Func {
    60  			return false
    61  		}
    62  		return true
    63  	}
    64  	return true
    65  }