面试题答案
一键面试1. 直接遍历赋值
- 实现方式:通过
for
循环遍历源切片,将每个元素逐一赋值给目标切片。
func deepCopyByLoop(src []int) []int {
dst := make([]int, len(src))
for i, v := range src {
dst[i] = v
}
return dst
}
- 性能优势:简单直观,对于基础类型切片在小规模数据下性能较好,因为只涉及基本的内存读写操作。
- 性能劣势:对于大规模数据,由于是逐元素拷贝,随着数据量增大,开销会线性增长,性能会逐渐下降。
- 适用场景:小规模基础类型切片的拷贝,代码简单,易于维护,对性能要求不是极高的场景。
2. 使用copy
函数
- 实现方式:利用Go语言内置的
copy
函数,该函数会将源切片数据高效地复制到目标切片。
func deepCopyByCopy(src []int) []int {
dst := make([]int, len(src))
copy(dst, src)
return dst
}
- 性能优势:在Go语言中,
copy
函数经过优化,在处理大规模基础类型切片时性能较好。它能够利用底层系统的特性,以较快的速度完成数据拷贝,相比直接遍历赋值通常有更好的性能表现。 - 性能劣势:对于包含复杂类型(如指针、结构体中含有指针等)的切片,如果只是简单使用
copy
,可能只是浅拷贝。需要额外处理来实现深拷贝,增加了代码复杂性。 - 适用场景:大规模基础类型切片的拷贝场景,因为其高效性,是基础类型切片拷贝的首选方式。
3. 使用encoding/gob
包
- 实现方式:通过将切片编码为字节流,再解码成新的切片。
func deepCopyByGob(src []int) ([]int, error) {
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
err := enc.Encode(src)
if err != nil {
return nil, err
}
var dst []int
dec := gob.NewDecoder(&buf)
err = dec.Decode(&dst)
if err != nil {
return nil, err
}
return dst, nil
}
- 性能优势:可以处理复杂类型切片的深拷贝,无需手动处理每个复杂类型的嵌套结构,能保证数据的深拷贝完整性。
- 性能劣势:性能开销较大,编码和解码过程涉及序列化和反序列化,对于大规模数据拷贝效率较低,而且还需要处理可能的错误。
- 适用场景:适用于包含复杂类型且对数据一致性要求严格,对性能要求相对不高的场景,比如在网络传输数据的编解码,数据持久化等场景。
4. 使用json.Marshal
和json.Unmarshal
- 实现方式:先将切片进行JSON序列化,再反序列化得到新的切片。
func deepCopyByJSON(src []int) ([]int, error) {
data, err := json.Marshal(src)
if err != nil {
return nil, err
}
var dst []int
err = json.Unmarshal(data, &dst)
if err != nil {
return nil, err
}
return dst, nil
}
- 性能优势:同样可以处理复杂类型切片的深拷贝,而且JSON格式具有通用性,在与其他系统交互时方便数据传输。
- 性能劣势:性能较低,JSON编解码过程相对复杂,对于大规模数据拷贝会消耗较多时间和资源。并且如果结构体中有不支持JSON序列化的字段会导致失败。
- 适用场景:适用于与外部系统(如HTTP API交互)需要以JSON格式传输数据,并且对数据进行深拷贝的场景,在这种场景下,JSON格式的通用性比性能更重要。
综上所述,当处理大规模基础类型切片时,优先选择copy
函数,因为其性能高效且实现简单;当处理包含复杂类型且对性能要求不高,但对数据一致性和通用性有要求时,可选择encoding/gob
或json.Marshal
和json.Unmarshal
;对于小规模基础类型切片,直接遍历赋值也可满足需求且代码简单。