Blockchain

[Solidity] 6.매핑(Mapping)과 배열(Array)

clolee 2025. 4. 17. 23:26

✅ 6. 매핑(Mapping)과 배열(Array)

Solidity의 데이터 저장 구조의 핵심

📌 1. 매핑 (Mapping)

✅ 정의

Solidity의 핵심 자료구조.
Key → Value 쌍으로 데이터를 저장하며, 해시테이블처럼 작동합니다.

mapping(address => uint) public balances;
  • balances[0x123...] = 100; 처럼 사용
  • 기본값 자동 초기화 (해당 키가 없으면 0 반환)

✅ 특징

특징 설명
검색 빠름 해시 기반으로 즉시 접근
전체 순회 불가 키 목록을 직접 저장하지 않으면 전체 조회 불가
기본값 존재 존재하지 않는 키에 접근 시에도 오류 발생하지 않음 (기본값 반환)
중첩 가능 mapping(address => mapping(uint => bool)) 가능

✅ 실무 예시

mapping(address => bool) public hasVoted;
mapping(address => mapping(uint => uint)) public stakeByPool;

📌 2. 배열 (Array)

✅ 정의

같은 타입의 요소들을 순차적으로 나열하는 자료구조

uint[] public numbers;

✅ 동적 배열 vs 정적 배열

유형 예시 특징
동적 배열 uint[] 길이 가변적 (push, pop 사용 가능)
정적 배열 uint[10] 고정 크기, 길이 변경 불가

✅ 배열 함수

함수 설명
.length 배열 길이 반환
.push(val) 끝에 요소 추가 (동적만 가능)
.pop() 마지막 요소 제거
arr[i] 인덱스 접근
delete arr[i] 값 제거 (단, 배열 크기는 유지됨)

✅ 예시

uint[] public values;

function addValue(uint _val) public {
    values.push(_val);
}

function getValue(uint index) public view returns (uint) {
    return values[index];
}

📌 3. 매핑 + 배열 조합 패턴 (실무 핵심)

전체 사용자 데이터를 순회하거나 삭제할 수 없기 때문에
매핑으로 빠른 접근 + 배열로 인덱스 관리 패턴이 매우 자주 사용됩니다.

mapping(address => uint) public balances;
address[] public holders;

function deposit() public payable {
    if (balances[msg.sender] == 0) {
        holders.push(msg.sender); // 최초 입금자만 등록
    }
    balances[msg.sender] += msg.value;
}

📌 4. 매핑 + Struct 조합

struct User {
    string name;
    uint score;
}

mapping(address => User) public users;
  • 필드 접근: users[msg.sender].name

📌 5. 배열 삭제의 주의점

delete arr[1];  // 해당 인덱스의 값은 초기화되지만
// 배열 길이는 그대로! → arr.length 그대로 유지됨

→ 정렬, 재배치 필요 시 for 반복문으로 수동 처리


✅ 실전 예제

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Registry {
    struct Info {
        string name;
        uint age;
    }

    mapping(address => Info) public infoMap;
    address[] public registeredUsers;

    function register(string memory _name, uint _age) public {
        if (bytes(infoMap[msg.sender].name).length == 0) {
            registeredUsers.push(msg.sender);
        }

        infoMap[msg.sender] = Info(_name, _age);
    }

    function getUserCount() public view returns (uint) {
        return registeredUsers.length;
    }
}

🧠 실무 팁 정리

항목 설명
매핑은 개별 접근에 적합 반복 불가, 전체 조회하려면 배열 필요
배열은 순회에 적합 특정 값 찾기는 비효율적 (O(n))
매핑 + 배열 보편적인 실무 패턴
delete는 요소만 제거 길이는 그대로, 재배치 필요
mapping + struct 모델링할 때 가장 흔히 쓰임

✅ [6단계 요약]

항목 설명
mapping(key => value) 주소 → 값, 토큰ID → 소유자 등
uint[], address[] 순서가 중요한 데이터
조합 사용 mapping + array, mapping + struct
반복문으로 배열 탐색 가스 비용 높으니 꼭 필요할 때만