프로그래밍Go 프로그래머

Go에서 내장 함수 append, len 및 cap는 무엇이며, 언어 수준에서 어떻게 작동하며, 그 사용과 관련된 슬라이스의 숨겨진 위험은 무엇입니까?

Hintsage AI 어시스턴트로 면접 통과

답변

Go에서 내장 함수 append, lencap는 슬라이스 작업 시 중요한 역할을 합니다.

  • **len(slice)**는 슬라이스의 요소 수를 반환합니다.
  • **cap(slice)**는 슬라이스의 용량 — 새로운 메모리 할당 전 최대 요소 수를 반환합니다.
  • **append(slice, elems ...T)**는 용량이 부족한 경우 새로운 배열(그리고 따라서 새로운 기저 저장소)을 생성하여 슬라이스 전파의 의미를 예기치 않게 변경할 수 있습니다.

예:

arr := []int{1,2,3} arr2 := append(arr, 4) // arr2는 cap(arr)에 따라 동일한 또는 새로운 backing array일 수 있습니다.

세부 사항:

  • 다른 슬라이스(또는 원본 배열)에서 "잘라낸" 슬라이스에 append를 수행하면 부작용이 발생할 수 있습니다: 원래 데이터가 변경될 수 있습니다.
  • 슬라이스를 len/cap 함수에 전달하면 "가시적인" 부분에 대해서만 작동합니다.
  • cap을 초과한 append 시 새로운 배열이 생성되고 원래 배열은 건드리지 않습니다.

트릭 질문

슬라이스에서 "일부를 잘라내고" append를 통해 요소를 추가하면 원래 배열에 영향을 미칩니까?

답변: cap이 허용되면 append는 원래 배열의 "끝"에 요소를 기록하며, 이는 동일한 배열을 참조하는 모든 슬라이스에 대해 변경 사항이 보입니다.

예:

a := []int{1,2,3,4} b := a[:2] // [1 2], len=2, cap=4 b = append(b, 10) // a가 변경됨: a -> [1, 2, 10, 4]

실제 오류 사례


이야기

팀은 자식 슬라이스에 요소를 추가했는데, 원래 배열의 데이터가 예상치 않게 변경되어 비즈니스 논리에 불일치가 발생하고 사용자 간 작업 분배에서 디버깅이 매우 어려운 버그가 발생했습니다.


이야기

큰 슬라이스에서 append를 여러 번 호출할 때 새로운 배열이 항상 새로 할당될 것이라고 예상했지만, 실제로 시스템의 여러 부분이 동일한 "backing array"로 계속 작동하여 경합 조건과 데이터 손상을 유발했습니다.


이야기

개발자는 make를 사용하여 고정 크기의 슬라이스를 할당했지만 인수를 잘못 바꿨습니다: make([]int, cap, len). 그 결과, 용량을 기준으로 한 논리가 예기치 않게 길이를 기준으로 작동하여 s[0:len]의 경계를 초과할 때 패닉을 유발했습니다.