ProgramaciónDesarrollador Go

¿Cómo funciona copy() en Go al copiar slices? ¿Cuáles son las características, limitaciones y efectos inesperados relacionados con el aumento de la longitud y capacidad del slice? ¿Qué ocurre al superponer slices y al intentar copiarlos con superposición?

Supere entrevistas con el asistente de IA Hintsage

Respuesta

La función copy(dst, src []T) int copia elementos de src a dst.

  • Devuelve la cantidad de elementos copiados: min(len(dst), len(src)).
  • La copia se realiza indexada: los elementos src[i] se copian a dst[i].
  • Se copian los contenidos (valores), no punteros a objetos.

Aspectos y limitaciones:

  • Si los slices se superponen (por ejemplo, uno es un subarray del otro), la copia se realiza como si primero se tomara un fragmento de los valores originales y luego se copiara (no hay garantías de corrección con superposición).
  • Si dst tiene una longitud menor que src, solo se copiará la cantidad de datos que permita la longitud de dst.
  • Si dst tiene una capacidad mayor que su longitud, ¿ampliará copy el slice? — No, solo se considera la longitud de len(dst). Para ampliar — use append previamente.

Ejemplo:

a := []int{1,2,3,4,5} b := make([]int, 3) copy(b, a) // b: [1 2 3]

Superposición:

x := []int{1,2,3,4} copy(x[1:], x[:3]) // [1 1 2 3]

Pregunta engañosa

¿Puede copy() usarse para aumentar la longitud del slice? ¿Qué ocurrirá si se pasa a copy un slice de destino de mayor capacidad, pero menor longitud de la necesaria?

Respuesta:

  • copy() no cambia la longitud del slice de destino — solo copia hasta len(dst)
  • Si dst tiene capacidad mayor que la longitud, amplíelo primero con dst = dst[:newLen], luego use copy()

Ejemplo, a menudo no evidente:

a := []int{1,2,3} b := make([]int, 0, 5) copy(b, a) // b seguirá vacío, ya que len(b)==0 b = b[:len(a)] copy(b, a) // ahora b: [1,2,3]

Ejemplos de errores reales debido al desconocimiento de los aspectos de este tema


Historia

En el proyecto, copiaron datos de un slice a otro, suponiendo que copy ampliaría automáticamente la longitud de dst a la necesaria. Esto no ocurrió, los elementos no se copiaron, y en consecuencia, en la respuesta de la API llegaban datos nulos. El error se encontró solo después de comparar las longitudes de los slices — el problema fue que dst tenía una gran capacidad, pero la longitud era 0.


Historia

Parte del microservicio trabajaba con slices superpuestos, suponiendo erróneamente que copy siempre funcionaría correctamente. Como resultado, la copia hacia adelante destruía los datos originales, aparecían errores "invisibles" al trabajar con buffers. Se resolvió utilizando un buffer temporal (copy(tmp, src), luego copy(dst, tmp)).


Historia

Un ingeniero optimizaba el array usando copy para organizar datos entre slices. Esperaba que copy ajustara la longitud de dst. Resultó que eso no ocurre, y comenzaron a aparecer pánicos y accesos fuera de los datos significativos — olvidaron cambiar correctamente la longitud del slice antes de la copia.