상세 컨텐츠

본문 제목

15. Rust는 차용(빌려줌) - Borrowing

Rust를 처음부터 배우세요

by 러스트코리아 2024. 11. 15. 19:53

본문

반응형

이전 장에서는 소유권 변경에 대해 알아보고  에 할당된 변수 에 소유권이 있다는 것을 배웠습니다 .

이전 장에서는 함수가 호출된 후에도 변수가 여전히 소유권을 갖고 있는지 확인하기 위해 문자열 변수 및 벡터 변수와 같은 소유권 변수를 함수에 매개변수로 전달하기도 했습니다. 함수 내에서 변수를 반환했습니다.

이 과정은 우리의 부담을 줄여줄 뿐만 아니라, 우리를 점점 더 사용하기 어렵게 느끼게 만듭니다.

사용하는 과정에서 차용 소유권 이나 임대 소유권 개념을 지원하면 어떨까 하는 생각을 해왔습니다 .

소유권이 있는 변수를 함수에 매개변수로 전달하면 소유권이 일시적으로 임대되며, 함수 실행 후 소유권이 자동으로 복구됩니다. 실생활에서와 마찬가지로 도구를 다른 사람에게 임시로 빌려주고, 사용이 끝나면 돌려줄 수 있습니다.

Rust에 대한 더 깊은 이해를 통해 나는 Rust 언어 개발자들이 바보가 아니며, 소유권 차용이라는 개념도 생각했다는 것을 느꼈습니다.

Rust는 소유권 차용을 지원합니다 . 소유권이 있는 변수가 함수에 전달되면 소유권이 함수의 매개변수에 빌려지고 함수가 반환될 때 소유권이 자동으로 회수됩니다.

다음 코드에서는 이전 장에서 소유권을 복구하기 위해 소유권 이전 규칙을 사용하지 않았으므로 프로그램에서 오류를 보고합니다.

  1. fn main(){
  2.  
  3. let v = vec![10,20,30]; // 벡터를 선언하면 변수 v가 ​​데이터의 소유권을 갖습니다.
  4. print_vector(v);
  5. println!("{}",v[0]); // 이 줄은 오류를 보고합니다
  6. }
  7.  
  8. fn print_vector(x:Vec<i32>){
  9. println!("Inside print_vector function {:?}",x);
  10. }

위의 코드에서는 main()과 print_Vector()라는 두 가지 함수를 정의했는데, 전자는 애플리케이션의 진입 함수이고 후자는 벡터를 출력하는 데 사용됩니다.

main() 함수에서 벡터를 정의하고 이 벡터를 print_Vector()에 매개변수로 전달합니다. 매개변수를 전달하면 소유권 이전이 트리거되기 때문입니다. 따라서 v가 print_Vector() 함수에 전달되면 데이터의 소유권이 v에서 매개변수 x로 이전됩니다.

그러나 함수가 반환되면 x에 의한 데이터의 소유권을 v 변수로 다시 전송하지 않으므로 위 코드를 컴파일할 때 오류가 보고됩니다.

  1. error[E0382]: borrow of moved value: `v`
  2. --> src/main.rs:5:18
  3. |
  4. 3 | let v = vec![10,20,30]; // 벡터를 선언하면 변수 v가 ​​데이터의 소유권을 갖습니다.
  5. | - move occurs because `v` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
  6. 4 | print_vector(v);
  7. | - value moved here
  8. 5 | println!("{}",v[0]); // 이 줄은 오류를 보고합니다
  9. | ^ value borrowed here after move
  10.  
  11. error: aborting due to previous error

이 예제를 반복하는 이유는 단어 수를 보충하기 위한 것이 아니라 몇 가지 수정만으로 프로그램을 실행할 수 있는 더 나은 솔루션을 갖게 되기 때문입니다.

15.1 차용이란 무엇입니까?

빌리거나 빌려주는 것은 나에게 자세히 설명할 필요가 없습니다. 그것은 매우 간단합니다. 그것은 다른 사람에게 일시적으로 빌려주고, 사용한 후에는 돌려주어야 한다는 것을 의미합니다.

여기서 핵심은 빌림과 반환이라는 두 단어입니다.

  • 빌리기: 다른 사람에게 무언가를 빌려준 후 일시적으로 해당 물건의 소유권을 잃습니다(실제로는 사용할 권리를 잃습니다).
  • 돌려주기: 다른 사람에게서 빌린 물건은 스스로 돌려주어야 합니다. 돌려주지 않으면 스스로 가져가는 것이 좋은 습관입니다.

빌리고, 빌리고, 반환하는 개념을 이해하고 나면 Rust 언어에서 Borrowing 의 개념이 매우 명확해질 것입니다.

Rust 언어에서 차용은 매개변수로 임시 사용하기 위해 한 함수에서 다른 함수로 변수를 전달하는 것입니다.

동시에 Rust는 함수의 매개변수가 해당 범위를 벗어날 때 원래 전달된 변수에 소유권을 반환해야 한다는 자동 반환 개념도 언급합니다. 이 과정에서 우리는 다음을 정의해야 합니다. 함수의 매개변수는 &variable_name으로, 매개변수를 동시에 전달하는 경우에는 &variable_name을 전달해야 합니다.

C++ 언어의 관점에서 볼 때 함수의 매개변수를 참조로 정의하고 동시에 변수의 참조를 전달하는 것입니다.

차용 또는 참조의 개념으로 위 코드를 실행하려면 두 곳만 수정하면 됩니다.

  1. fn print_vector(x:&Vec<i32>){ // 1. 첫 번째 단계는 참조를 허용하는 매개변수를 정의하는 것입니다.
  2. println!("Inside print_vector function {:?}",x);
  3. }
  4.  
  5. fn main(){
  6.  
  7. let v = vec![10,20,30]; //벡터를 선언하면 변수 v가 ​​데이터의 소유권을 갖습니다.
  8. print_vector(&v); // 두 번째 단계는 변수의 참조를 함수에 전달하는 것입니다.
  9. println!("{}",v[0]); // 이 줄은 오류를 보고합니다
  10. }

위의 Rust 코드를 컴파일하고 실행하면 출력 결과는 다음과 같습니다.

  1. Inside print_vector function [10, 20, 30]
  2. 10

15.2 변경 가능한 참조

차용 또는 참조는 기본적으로 읽기 전용입니다. 즉, 참조된 변수의 값을 수정할 수 없습니다.

예를 들어 다음 코드는

  1. fn add_one(e: &i32) {
  2. *e+= 1;
  3. }
  4.  
  5. fn main() {
  6. let i = 3;
  7. println!("before {}",i);
  8. add_one(&i);
  9. println!("after {}", i);
  10. }

위의 Rust 코드를 컴파일하고 실행하면 출력 결과는 다음과 같습니다.

  1. error[E0594]: cannot assign to `*e` which is behind a `&` reference
  2. --> src/main.rs:2:4
  3. |
  4. 1 | fn add_one(e: &i32) {
  5. | ---- help: consider changing this to be a mutable reference: `&mut i32`
  6. 2 | *e+= 1;
  7. | ^^^^^^ `e` is a `&` reference, so the data it refers to cannot be written
  8.  
  9. error: aborting due to previous error

add_one() 함수에서 참조된 변수를 +1하려고 했지만 컴파일이 실패했습니다.

오류 메시지에서 알 수 있듯이 실패 이유는 기본적으로 참조를 편집할 수 없기 때문입니다.

Rust에서 변수를 편집 가능하게 만드는 유일한 방법은 변수에 mut 키워드를 추가하는 것입니다.

따라서 위의 코드를 다음과 같이 변환할 수 있습니다.

  1. fn add_one(e: &mut i32) {
  2. *e+= 1;
  3. }
  4.  
  5. fn main() {
  6. let mut i = 3;
  7. println!("before {}",i);
  8. add_one(&mut i);
  9. println!("after {}", i);
  10. }

위의 Rust 코드를 컴파일하고 실행하면 출력 결과는 다음과 같습니다.

  1. before 3
  2. after 4

위 코드에서 볼 수 있듯이 차용 또는 참조된 변수를 변경하려면 다음 세 가지 요구 사항을 충족해야 합니다.

  1. 변수 자체는 변경 가능합니다. 즉, 정의할 때 mut 키워드를 추가해야 합니다.
  2. 함수의 매개변수도 변경 가능하도록 정의하고 차용 또는 참조를 추가해야 합니다. 즉, &mut 키워드를 추가해야 합니다.
  3. 차용 또는 참조도 변경 가능하도록 선언해야 합니다. 즉, 매개변수를 전달할 때 &mut 키워드를 추가해야 합니다.

위의 세 가지 조건 중 하나라도 충족되지 않으면 오류가 보고됩니다. 예를 들어 세 번째 조건이 충족되지 않는 경우

  1. fn add_one(e: &mut i32) {
  2. *e+= 1;
  3. }
  4.  
  5. fn main() {
  6. let mut i = 3;
  7. println!("before {}",i);
  8. add_one(& i);
  9. println!("after {}", i);
  10. }

오류 메시지는 다음과 같습니다

  1. error[E0308]: mismatched types
  2. --> src/main.rs:8:12
  3. |
  4. 8 | add_one(& i);
  5. | ^^^ types differ in mutability
  6. |
  7. = note: expected type `&mut i32`
  8. found type `&{integer}`
  9.  
  10. error: aborting due to previous error

참고: 변경 가능한 참조는 변경 가능한 변수에서만 작동할 수 있습니다.

15.2.1 예: 문자열에 대한 가변 참조

위의 예에서는 기본 데이터 유형을 작업하고 있는데, 힙에 할당된 변수라면 어떻게 될까요? 문자열과 같은.

실제로 힙에 할당된 변수의 차용이나 참조는 기본 타입의 변수와 동일합니다.

  1. fn main() {
  2. let mut name:String = String::from("TutorialsPoint");
  3. display(&mut name); // 변경 가능한 참조 전달
  4. println!("The value of name after modification is:{}",name);
  5. }
  6.  
  7. fn display(param_name:&mut String){
  8. println!("param_name value is :{}",param_name);
  9. param_name.push_str(" Rocks"); // 문자열을 수정하고 일부 문자를 추가합니다.
  10. }

위의 Rust 코드를 컴파일하고 실행하면 출력 결과는 다음과 같습니다.

  1. param_name value is :TutorialsPoint
  2. The value of name after modification is:TutorialsPoint Rocks
현재 콘텐츠 저작권은 chapin666 또는 그 계열사에 있습니다.
반응형

'Rust를 처음부터 배우세요' 카테고리의 다른 글

17. Rust 구조 (Struct)  (0) 2024.11.15
16. Rust 슬라이스  (0) 2024.11.15
14. Rust 소유권  (0) 2024.11.15
13. Rust 배열  (0) 2024.11.15
12. Rust 듀플(tuple)  (0) 2024.11.15

관련글 더보기