Médio Go

Fatiando e observando o aliasing

Enunciado

Dado nums := []int{1, 2, 3, 4, 5}, crie um sub-slice sub := nums[1:4] e imprima nums, sub e o cap(sub). Depois altere sub[0] = 99 e imprima nums novamente para mostrar o compartilhamento.

Requisitos

  • Criar o slice original com 5 inteiros.
  • Criar sub usando fatiamento nums[1:4].
  • Imprimir cap(sub) (deve ser 4).
  • Mostrar que alterar sub[0] muda nums[1].

Código inicial

package main

import "fmt"

func main() {
	nums := []int{1, 2, 3, 4, 5}
	// TODO: crie sub, imprima tudo e altere sub[0]
}

Saída esperada

nums=[1 2 3 4 5] sub=[2 3 4] cap(sub)=4
após alterar: nums=[1 99 3 4 5] sub=[99 3 4]
Ver dica

nums[1:4] pega os índices 1, 2 e 3. A capacidade vai do índice inicial até o fim do array subjacente.

Mostrar solução
package main

import "fmt"

func main() {
	nums := []int{1, 2, 3, 4, 5}

	// sub enxerga os índices 1..3 do mesmo array de nums
	sub := nums[1:4]
	fmt.Printf("nums=%v sub=%v cap(sub)=%d\n", nums, sub, cap(sub))

	// sub[0] é o mesmo elemento que nums[1]
	sub[0] = 99
	fmt.Printf("após alterar: nums=%v sub=%v\n", nums, sub)
}

Passo a passo

  1. nums é um slice de 5 inteiros; o compilador cria um array subjacente com esses valores.
  2. nums[1:4] cria um novo slice que aponta para o elemento de índice 1 do array, com len=3 (índices 1, 2, 3).
  3. cap(sub) é 4 porque, a partir do índice 1, ainda existem 4 posições até o fim do array (índices 1, 2, 3, 4).
  4. O primeiro Printf mostra os dois slices e a capacidade.
  5. sub[0] = 99 escreve na posição que nums enxerga como índice 1, então nums[1] vira 99.
  6. O segundo Printf confirma que os dois slices refletem a mudança.

Por que funciona

Fatiar não copia dados: cria um novo cabeçalho (ponteiro, len, cap) sobre o mesmo backing array. Por isso alterações em elementos compartilhados aparecem nos dois slices. É o famoso aliasing.

Erros comuns

  • Achar que sub := nums[1:4] copiou os valores: não copiou, é uma visão.
  • Esperar cap(sub) == len(sub): a capacidade vai até o fim do array, não até o fim do slice.
  • Tentar acessar sub[3]: len(sub) é 3, então o índice válido vai só até 2, mesmo com cap=4.

Outra forma de resolver

Se você quiser uma cópia independente, use slices.Clone (Go 1.21+):

sub := slices.Clone(nums[1:4])
sub[0] = 99 // não afeta nums

Prefira cópia quando for modificar sem querer afetar o original.

Saída esperada

nums=[1 2 3 4 5] sub=[2 3 4] cap(sub)=4
após alterar: nums=[1 99 3 4 5] sub=[99 3 4]