본문 바로가기

Rust

[Rust] 포인터의 종류와 사용방법

반응형

Rust에서는 다양한 종류의 포인터를 제공합니다. 이 포인터들은 메모리 안전성, 소유권, 뮤터불리티 등 다양한 측면에서 사용됩니다. 아래에 주요 포인터 타입에 대한 설명을 제공하겠습니다.

Rust에서는 여러 종류의 포인터를 제공합니다. 각각의 포인터는 메모리 안전성을 보장하는 데 다양한 방법을 사용합니다. 아래 테이블에서 주요 포인터 타입의 특징을 비교하겠습니다.

 

먼저 들어가기 전에 뮤터블과 (Mutable)과 이뮤터블(Immutable)의 간략히 짚고 갑니다. 아래는 비교한 표입니다.

변경 가능한 변경 불가능한
변수 선언 let mut x = 5; let x = 5;
값 변경 가능 (x = 6;) 불가능
배열/벡터 수정 가능 (vec.push(1);) 불가능
메모리 안정성 상대적으로 낮음 높음
데이터 경쟁 조건 발생 가능성 있음 발생 가능성 없음
Rust에서의 중요성 소유권 모델에서 주의 필요 소유권 모델에서 안전

이 표는 뮤터블과 이뮤터블의 기본적인 차이와 Rust에서의 의미를 간략하게 비교하고 있습니다. Rust의 소유권 모델에서는 이 두 개념이 중요한 역할을 하며, 이를 통해 메모리 안정성과 병렬 프로그래밍의 안정성이 향상됩니다.

&T와 &mut T (참조와 뮤터블 참조)

  • &T: 이뮤터블 참조, 즉 읽기 전용 참조입니다. 이 참조를 통해 데이터를 수정할 수 없습니다.
  • &mut T: 뮤터블 참조로, 이 참조를 통해 데이터를 수정할 수 있습니다.

Box<T>

  • Box<T>: 힙에 데이터를 저장합니다. Box는 단일 소유자를 가지며, 데이터의 크기가 컴파일 타임에 알려져 있어야 합니다.

Rc<T>와 Arc<T> (참조 카운팅 포인터)

  • Rc<T>: "Reference Counted"의 약자로, 단일 스레드 환경에서 여러 소유자를 가질 수 있습니다.
  • Arc<T>: "Atomic Reference Counted"의 약자로, 멀티 스레드 환경에서 안전하게 사용할 수 있습니다.

RefCell<T>

  • RefCell<T>: 런타임에 뮤터불리티를 변경할 수 있게 해주는 포인터입니다. 컴파일 타임에 뮤터불리티를 검사할 수 없는 경우에 유용합니다.

Unsafe<T>

  • *const T와 *mut T: 이것은 "원시 포인터"라고도 하며, Rust의 안전성 보장을 우회합니다. 주로 FFI (외부 함수 인터페이스)나 시스템 호출에서 사용됩니다.

각각의 포인터 타입은 특정 목적과 상황에 따라 설계되었습니다. 예를 들어, Box<T>는 힙 할당을 필요로 하는 큰 데이터 구조나 소유권을 명확히 해야 하는 경우에 사용됩니다. Rc<T>와 Arc<T>는 여러 곳에서 읽기 전용으로 접근해야 하는 데이터에 사용됩니다. RefCell<T>은 런타임에 뮤터불리티가 변경될 수 있는 상황에서 사용됩니다. 원시 포인터는 극단적인 최적화나 시스템 수준의 프로그래밍이 필요할 때 사용됩니다.

위 내용을 표로 다시 정리한 부분입니다.

&T Immutable 없음 높음 데이터 읽기 빠름, 안전함 수정 불가능
&mut T Mutable 없음 높음 데이터 수정 빠름, 안전함 하나의 뮤터블 참조만 허용됨
Box<T> 선택적 있음 높음 힙 할당 소유권 명확, 안전함 힙 할당/해제 비용 발생
Rc<T> Immutable 있음 높음 여러 소유자 (단일 스레드) 참조 카운팅으로 안전성 보장 뮤터불리티 없음, 오버헤드 있음
Arc<T> Immutable 있음 높음 여러 소유자 (멀티 스레드) 멀티 스레드 안전 뮤터불리티 없음, 오버헤드 있음
RefCell<T> 런타임 없음 중간 런타임 뮤터불리티 런타임에서 뮤터불리티 변경 가능 런타임 비용, 패닉 가능성 있음
Unsafe<T> 선택적 있음 낮음 FFI, 배열 접근 등 최적화 가능, 유연함 안전성 보장되지 않음

아래는 각각의 포인터들에 대한 예제입니다. 

&T와 &mut T

let x = 5; 
let y = &x; // 이뮤터블 참조 
let z = &mut x; // 뮤터블 참조 (컴파일 에러, x가 뮤터블이 아님)

Box<T>

let x = Box::new(5);

Rc<T>와 Arc<T>

use std::rc::Rc; 
let x = Rc::new(5); 
let y = x.clone();

RefCell<T>

use std::cell::RefCell; 
let x = RefCell::new(5); 
*x.borrow_mut() += 1;

Unsafe<T>

let x: i32 = 42; 
let r: *const i32 = &x; 
unsafe { println!("r points to: {}", *r); }

Rust는 메모리 안전성과 다양한 요구 사항을 충족하기 위해 여러가지 포인터들이 있습니다. 이 포인트들의 사용법을 익히고 적절한 포인터 타입을 선택하는 것은 중요한 일입니다. 

반응형

'Rust' 카테고리의 다른 글

[Rust] Option<T> 의 사용방법에 대하여  (2) 2023.12.06
Rust in Jupyter notebook  (0) 2023.12.04
[Rust] Clap과 커맨드 라인 argument 다루기  (0) 2023.09.07
[Rust] Cargo 간단한 사용법  (0) 2023.09.05
[RUST] xlsxwriter  (0) 2023.07.24