💻 프로그래밍

보로잉

Borrowing

Rust의 참조 시스템. 소유권을 이전하지 않고 값을 빌려 사용. 불변/가변 참조로 구분.

📖 상세 설명

보로잉(Borrowing)은 Rust 프로그래밍 언어의 핵심 메모리 관리 개념으로, 값의 소유권을 이전하지 않고 참조를 통해 데이터에 접근하는 방식입니다. 이는 C/C++의 포인터와 유사하지만, 컴파일 타임에 안전성이 보장됩니다. 보로잉을 통해 여러 코드 블록에서 같은 데이터를 효율적으로 사용할 수 있습니다.

보로잉에는 불변 참조(immutable reference, &T)와 가변 참조(mutable reference, &mut T) 두 가지 유형이 있습니다. 불변 참조는 여러 개가 동시에 존재할 수 있지만 데이터를 수정할 수 없고, 가변 참조는 단 하나만 존재할 수 있으며 데이터 수정이 가능합니다. 이 규칙이 데이터 경쟁 조건을 원천적으로 방지합니다.

보로잉의 핵심 규칙은 "여러 불변 참조 또는 하나의 가변 참조"입니다. 즉, 불변 참조와 가변 참조가 동시에 존재할 수 없으며, 이는 컴파일러가 엄격하게 검사합니다. 이 규칙 덕분에 멀티스레드 환경에서도 안전한 코드를 작성할 수 있습니다.

참조의 수명(lifetime)도 보로잉의 중요한 개념입니다. 참조는 원본 데이터보다 오래 살아있을 수 없으며, 보로우 체커가 이를 자동으로 검증합니다. 함수 매개변수나 반환값에서 참조를 사용할 때 수명 주석을 명시해야 하는 경우도 있습니다.

💻 코드 예제

// Rust 보로잉 예제

fn main() {
    let mut s = String::from("hello");

    // 불변 참조 (여러 개 가능)
    let r1 = &s;
    let r2 = &s;
    println!("불변 참조들: {}, {}", r1, r2);

    // 가변 참조 (하나만 가능)
    let r3 = &mut s;
    r3.push_str(", world");
    println!("가변 참조: {}", r3);

    // 함수에 참조 전달
    let len = calculate_length(&s);
    println!("'{}'의 길이: {}", s, len);

    // 가변 참조로 수정
    change(&mut s);
    println!("수정 후: {}", s);
}

// 불변 참조를 받아 읽기만 함
fn calculate_length(s: &String) -> usize {
    s.len()
}

// 가변 참조를 받아 수정
fn change(s: &mut String) {
    s.push_str("!");
}

🗣️ 실무 대화 예시

기술 리더: "이 로직에서 데이터 복사가 많이 일어나고 있어요. 성능이 걱정되는데요."

개발자: "보로잉을 활용해서 복사 대신 참조로 전달하면 메모리 할당을 줄일 수 있습니다."

기술 리더: "가변 참조가 필요한 부분도 있나요?"

개발자: "네, 업데이트 로직에서는 &mut로 전달하고, 조회만 하는 곳은 불변 참조를 쓰면 됩니다."

면접관: "Rust의 보로잉 규칙에 대해 설명해 주세요."

지원자: "보로잉은 소유권 이전 없이 값에 접근하는 방식입니다. 불변 참조는 여러 개 가능하지만, 가변 참조는 동시에 하나만 존재할 수 있습니다."

면접관: "왜 그런 제약이 있을까요?"

지원자: "데이터 레이스를 컴파일 타임에 방지하기 위함입니다. 여러 곳에서 동시에 읽거나, 한 곳에서만 쓰는 것이 보장되어 안전한 동시성을 구현할 수 있습니다."

리뷰어: "여기서 clone()을 호출하고 있는데, 불필요한 복사 같아요."

작성자: "보로잉 규칙 때문에 컴파일이 안 돼서 임시로 clone을 넣었습니다."

리뷰어: "참조의 스코프를 조정하면 해결될 것 같아요. 불변 참조 사용이 끝난 후에 가변 참조를 만들면 됩니다."

작성자: "아, NLL(Non-Lexical Lifetimes) 덕분에 그게 가능하군요. 수정하겠습니다."

⚠️ 주의사항

🔗 관련 용어

📚 더 배우기