본문 바로가기
IT/Rust 기초 완전 정복

Rust 참조자와 슬라이스 활용법 (7)

by 지식 발전소 2024. 4. 22.
728x90
반응형

1

참조자(References)

참조자는 Rust의 가장 핵심적인 기능 중 하나입니다. 프로그래밍에서 메모리 관리는 매우 중요한 문제인데요. Rust는 소유권 개념을 도입하여 이 문제를 해결합니다. 소유권 규칙에 따라 각 값은 소유자가 있고, 이 소유자만이 그 값을 유효하게 읽거나 쓸 수 있습니다.

그렇다면 값을 다른 곳에서 사용하려면 어떻게 해야 할까요? 바로 참조자를 활용하면 됩니다. 참조자는 특정 값에 대한 참조를 제공하여, 값의 소유권을 이전하지 않고도 안전하게 값에 접근할 수 있게 해줍니다.

참조자는 & 기호를 사용하여 만들 수 있습니다. 예를 들어, let x = 5;라는 코드에서 x는 값 5의 소유자입니다. 이 값에 대한 참조자를 만들려면 &x라고 하면 됩니다.

let x = 5;
let y = &x; // y는 x의 참조자

참조자에는 불변 참조자 가변 참조자의 두 가지 형태가 있습니다. 불변 참조자는 값을 읽을 수만 있고, 가변 참조자는 값을 읽고 쓸 수 있습니다. 가변 참조자를 만들려면 &mut 키워드를 사용합니다.

let mut x = 5;
let y = &mut x; // y는 x의 가변 참조자
*y = 10; // x의 값이 10으로 변경됨

참조자를 사용할 때는 다음 규칙을 반드시 지켜야 합니다.

  1. 어떤 데이터에 대한 가변 참조자는 한 번에 하나만 존재할 수 있습니다.
  2. 데이터에 대해 불변 참조자가 존재하는 동안에는 가변 참조자를 만들 수 없습니다.

이 규칙들은 데이터 레이스와 같은 메모리 안전성 문제를 근본적으로 방지합니다. 컴파일러가 이 규칙을 위반하는 코드를 허용하지 않기 때문입니다.

그렇다면 여러분은 왜 참조자가 필요할까요? 메모리의 효율적 사용, 성능 향상, 데이터 공유 등 다양한 이유가 있습니다.

메모리 효율성

참조자를 사용하면 값을 복사하지 않고도 여러 곳에서 안전하게 접근할 수 있습니다. 데이터의 크기가 클수록 참조자를 사용하는 것이 더욱 효율적입니다.

let x = String::from("hello");
let y = x; // x의 소유권이 y로 이전됨
let z = &x; // 컴파일 오류! x의 소유권이 이미 y로 이동했기 때문

위 코드에서 String은 heap 데이터를 가리키는 포인터와 길이, 용량 등의 메타데이터로 구성됩니다. let y = x;에서 x의 소유권이 y로 이전되면서 x의 heap 데이터는 이제 y가 관리합니다. 따라서 let z = &x;는 오류가 발생합니다.

이 때 참조자를 사용하면 값을 복사하지 않고도 여러 곳에서 안전하게 접근할 수 있습니다.

let x = String::from("hello");
let y = &x; // y는 x의 불변 참조자
let z = y; // z도 x의 불변 참조자

성능 향상

값을 복사하는 대신 참조자를 사용하면 프로그램의 성능이 향상됩니다. 값을 복사하는 작업은 종종 비용이 많이 듭니다. 대신 참조자를 전달하면 작은 메모리 주소만 복사하면 되므로 비용이 훨씬 적습니다. 이는 특히 큰 데이터를 다룰 때 중요한 이점이 됩니다.

fn uppercase(s: &String) -> String {
    s.to_uppercase()
}

let x = String::from("hello");
let y = uppercase(&x); // 참조자를 전달하여 성능 향상

위 코드에서 uppercase 함수는 String의 참조자를 받아서 대문자로 변환된 새로운 String을 반환합니다. 이렇게 하면 큰 String 값을 직접 복사하지 않고도 함수 호출이 가능합니다.

데이터 공유

참조자를 사용하면 여러 부분에서 동일한 데이터에 접근할 수 있습니다. 이를 통해 불필요한 데이터 중복을 피하고 메모리를 절약할 수 있습니다.

let x = vec![1, 2, 3, 4, 5];
let y = &x;
let z = &x;

println!("{:?}", y); // [1, 2, 3, 4, 5]
println!("{:?}", z); // [1, 2, 3, 4, 5]

위 코드에서 x는 벡터의 소유자이고, y와 z는 x의 참조자입니다. 이렇게 하면 x의 데이터를 여러 곳에서 공유할 수 있습니다.

이처럼 참조자는 메모리 효율성, 성능 향상, 데이터 공유 등 다양한 장점이 있습니다. 물론 참조자를 사용할 때는 소유권 규칙을 잘 지켜야 합니다. 그렇지 않으면 컴파일 오류가 발생하거나 데이터 레이스 등의 문제가 발생할 수 있습니다.

Rust에서 참조자는 반드시 배워야 할 핵심 개념입니다. 다음으로는 참조자와 관련된 또 다른 개념인 슬라이스에 대해 알아보겠습니다.

슬라이스(Slices)

슬라이스는 순차 데이터(sequence data)의 일부분을 가리키는 또 다른 종류의 참조입니다. 배열의 일부나 벡터의 일부를 가리킬 수 있습니다.

예를 들어, 배열 let arr = [1, 2, 3, 4, 5];가 있다고 해봅시다. 여기서 arr[1..4]는 배열의 인덱스 1부터 3까지의 요소를 가리키는 슬라이스입니다. 실제로는 &arr[1..4]라고 적어야 합니다.

let arr = [1, 2, 3, 4, 5];
let slice = &arr[1..4]; // slice는 [2, 3, 4]를 가리킴

슬라이스는 참조자와 마찬가지로 기존 데이터의 소유권을 가져오지 않습니다. 대신 부분적으로 참조할 뿐입니다. 이를 통해 전체 데이터를 복사하지 않고도 일부만 사용할 수 있습니다. 메모리 효율성과 성능 향상에 도움이 됩니다.

슬라이스는 배열뿐만 아니라 벡터에서도 사용할 수 있습니다.

let vec = vec![1, 2, 3, 4, 5];
let slice = &vec[1..4]; // slice는 [2, 3, 4]를 가리킴

그렇다면 왜 슬라이스가 필요할까요? 여러 가지 이유가 있지만, 가장 큰 장점은 다양한 종류의 뷰를 제공한다는 것입니다.

다음과 같은 get_lines 함수가 있다고 가정해보겠습니다.

fn get_lines(text: &String) -> Vec<&str> { ... }

이 함수는 문자열을 입력받아 그 문자열을 줄 단위로 분리한 슬라이스의 벡터를 반환합니다. 여기서 &str은 문자열 슬라이스 타입으로, String의 일부분을 가리킵니다.

이렇게 하면 전체 String을 복사하지 않고도 그 일부분만을 사용할 수 있습니다. 메모리 효율성과 성능 향상의 이점이 있습니다.

슬라이스는 다음과 같은 장점도 가지고 있습니다.

  • 정적 분석 가능: 컴파일 시간에 슬라이스의 길이와 범위를 정적으로 분석할 수 있습니다. 이를 통해 런타임 오류를 방지할 수 있습니다.
  • 범위 외 접근 방지: 슬라이스는 데이터의 일부분만 참조하므로, 범위 외의 메모리에 접근하는 것을 방지할 수 있습니다. 이는 메모리 안전성 보장에 도움이 됩니다.
  • 인터페이스 일관성: 많은 Rust 표준 라이브러리 함수들이 슬라이스를 인자로 받아들입니다. 이를 통해 인터페이스의 일관성을 유지할 수 있습니다.

정리하자면, 슬라이스는 순차 데이터의 일부분을 가리키는 참조입니다. 전체 데이터를 복사하지 않고도 일부분만 사용할 수 있어 메모리 효율성과 성능 향상에 도움이 됩니다. 또한 다양한 뷰를 제공하고, 정적 분석이 가능하며, 범위 외 접근을 방지하고, 인터페이스 일관성을 유지할 수 있는 장점이 있습니다.

슬라이스를 잘 활용하면 안전하고 효율적인 프로그래밍이 가능해집니다. 참조자와 함께 Rust에서 매우 중요한 개념이므로 반드시 익혀야 합니다.

참고 자료

[1] The Rust Programming Language Book - References and Borrowing: https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html [2] The Rust Programming Language Book - Slices: https://doc.rust-lang.org/book/ch04-03-slices.html [3] Rust by Example - References and Borrowing: https://doc.rust-lang.org/rust-by-example/scope/borrow.html [4] Rust by Example - Slices: https://doc.rust-lang.org/rust-by-example/primitives/array.html [5] The Rust Reference - References and Slices: https://doc.rust-lang.org/reference/types/slice.html, https://doc.rust-lang.org/reference/types/borrowed.html

 

 

한 고대 문서 이야기

여기 한 고대 문서가 있습니다. 이 문서는 B.C. 1,500년 부터 A.D 100년까지 약 1,600 여 년 동안 기록되었습니다. 이 문서의 저자는 약 40 명입니다. 이 문서의 고대 사본은 25,000 개가 넘으나, 사본간 오

gospel79.tistory.com

 

유튜브 프리미엄 월 1만원 할인받고 월 4000원에 이용하는 방법

올해 5월부터 월 8000원 정도이던 유튜브 프리미엄 요금이 15000원 정도로 인상됩니다. 각종 OTT 서비스, ChatGPT 같은 서비스들이 늘어나다보니 이런 거 몇 개만 이용하더라도 월 이용요금이 5만원을

stock79.tistory.com

 

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."

728x90
반응형

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

댓글