프로그래밍백엔드 개발자

Rust에서 변수를 함수에 전달할 때 move와 borrow의 차이점은 무엇인가요?

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

답변

변수가 함수에 전달될 때, 참조에 의해 전달될 수 있거나(대여, & 또는 &mut 사용) 이동(move)될 수 있습니다.

대여(Borrow): 데이터에 대한 참조가 전달됩니다. 함수 호출 후에도 데이터에 접근할 수 있지만, 불변 참조의 경우 내용물을 변경할 수 없고, 가변 참조의 경우에는 활성 참조가 하나만 존재해야 합니다.

fn read_length(s: &String) -> usize { s.len() }

이동(Move): 변수 전체가 함수로 "이동"됩니다. 전달한 후에는 원래 변수는 사용할 수 없게 되며 — 그것은 이동되었기 때문에, 접근을 시도하면 컴파일 오류가 발생합니다.

fn destroy(s: String) { println!("{}", s); } // s는 함수 종료 시 파괴됩니다. let s = String::from("world"); destroy(s); // s는 더 이상 사용할 수 없습니다.

이는 이중 메모리 해제를 방지하고 소유권과 관련된 다른 오류를 피하는 데 도움을 줍니다.

함정을 감춘 질문

이동 방식으로 값을 함수에 전달한 후 변수를 사용할 수 있나요?

아니요! 변수 값을 이동으로 전달한 후 — 예를 들어, String — 원래 변수가 무효화됩니다:

let s = String::from("abc"); consume(s); // s는 여기서 더 이상 유효하지 않습니다. println!("{}", s); // 컴파일 오류

많은 사람들이 이것을 복사 타입(예: i32)의 동작과 혼동하여, 변수가 전달된 후에도 여전히 유효하다고 생각합니다.

주제의 미세한 차이를 알지 못해 발생하는 실제 오류의 예


이야기

젊은 프로그래머가 String이 아닌 &String을 받아들이는 문자열 처리 함수를 작성했습니다. 결국 함수 호출 후 원래 문자열이 사용 불가능해져, 로그 서버에서 이중 로드 및 추가 메모리 할당 문제가 발생했습니다.


이야기

하나의 마이크로 서비스에서 중요한 자원이 이동(move)을 통해 여러 스레드에 전달되었고, 그 후 메인 스레드에서 이 자원에 접근하려는 시도가 컴파일 오류를 초래했습니다. 그래서 자원이 참조에 의해 전달되거나 Arc 유형의 래퍼를 통해 전달되도록 아키텍처를 급히 리팩토링해야 했습니다.


이야기

내부 이벤트 파서에서 데이터를 처리하는 동안 변수가 클로저로 빠르게 이동(moving)되었고, 그 이후 클로저 외부에서 이 변수에 대한 접근이 컴파일 오류를 일으켰습니다. 이 문제는 리뷰 중에만 발견되어, 지역 함수보다 더 오래 살아야 하는 데이터에 대해 대여를 반드시 사용해야 한다는 스타일이 도입되었습니다.