delete로 요소 제거
배열의 특정 칸 값을 비우고 싶을 때 delete 키워드를 사용합니다. 그런데 delete의 동작에는 초보자가 가장 많이 헷갈리는 함정이 하나 있습니다. 바로 길이가 줄어들지 않는다는 점입니다.
delete는 값을 기본값으로 되돌린다
delete numbers[i]는 인덱스 i의 값을 해당 타입의 기본값(uint은 0)으로 되돌립니다. 여기서 중요한 것은 delete가 배열의 길이를 줄이지 않는다는 점입니다. 해당 자리만 0으로 바뀔 뿐, 칸 수는 그대로 유지됩니다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract DeleteExample {
uint256[] public numbers = [10, 20, 30];
// numbers[1] 을 0으로 초기화 (length는 그대로 3)
function resetSecond() public {
delete numbers[1]; // [10, 0, 30]
}
// 배열 전체를 비움 (length가 0이 됨)
function clear() public {
delete numbers;
}
}요소 하나 vs 배열 전체
delete numbers[i]→ 인덱스i만 기본값으로. 길이 변화 없음([10, 0, 30]).delete numbers→ 배열 전체를 비움. 이때는 길이가 0이 됩니다.
이 차이를 혼동하면, 요소를 "지웠다"고 생각했는데 길이는 그대로라 반복문에서 0이 끼어드는 버그가 생깁니다.
delete numbers[1] 후에도 numbers.length는 여전히 3입니다. pop만이 length를 실제로
줄입니다. delete와 pop을 혼동하지 마세요.
길이까지 줄이는 swap and pop
값만 0으로 만드는 것이 아니라 길이까지 줄이며 중간 요소를 제거하려면, 지울 자리에 마지막 요소를 덮어쓴 뒤 pop으로 끝을 제거하는 swap and pop 기법을 흔히 씁니다.
function removeAt(uint256 i) public {
numbers[i] = numbers[numbers.length - 1]; // 마지막 값을 i로 이동
numbers.pop(); // 끝 요소 제거 → length -= 1
}swap and pop은 가스 효율이 좋지만 요소의 순서가 바뀝니다. 순서를 반드시 유지해야 한다면 뒤 요소를 한 칸씩 당겨야 하며 가스 비용도 더 큽니다.
정리하면 delete numbers[i]는 값만 초기화하고(길이 불변), delete numbers는 배열 전체를 비웁니다. 길이까지 줄이려면 pop 또는 swap and pop을 사용하세요.