불변 참조와 가변 참조.
mut 는 가변이라는 뜻이고, rust 에서는 기본이 불변, mut를 사용해야 값을 변경 가능하다.
C++은 기본이 가변이라는 것에 불변에 사용하는 const와 반대되는 개념이다.
rust에는 불변 참조와 가변 참조가 있다
가변 참조는 내가 다른 곳에서 사용하기 위해 변수를 선언할 때, 해당 값을 가져와서 그 값을 변경할 수 있는 것이고, 불변은 변수 선언 이후 참조 시 참조 값이 바뀔 수 없는 것. 불변 참조는 여럿 선언 가능하지만 가변 참조는 하나만 사용 가능하다. 그리고 불변과 가변 참조를 동시에 가질 수 없다.
참조는 소유권을 가져가지 않고, 원본이 유효한 동안에 사용 가능하다.
변수 lifetime
수명 파라미터는 ‘a 와 같이 유효한 기간을 표시한다.
- &T → 어떤 데이터의 참조지만, 그 참조가 유효한 기간을 <'a>로 표시 가능
- 수명 파라미터 'a는 **“이 참조는 최소 'a 동안 유효하다”**라는 의미
- 함수, 구조체, 메서드 등에서 입력 참조와 출력 참조 사이의 관계를 표현하는 데 사용
// x, y 둘 다 최소 'a 동안 살아있어야 하고
// 반환 참조도 최소 'a 동안 유효
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
b 객체의 <`a> 라는 뜻은 b 객체의 lifetime은 a라는 객체의 lifetime 이내라는 뜻
`static
static 이라는 말과 같이 프로그램 전체 실행 기간 동안 유효한다는 뜻.
C++ 의 static과 같은 내용
let s: &'static str = "hello";
자료형
- 자료형추가로, 사용자 정의 타입도 존재합니다.
1. 스칼라 타입 (Scalar Types)분류 예시 설명정수형 (Integer) i8, i16, i32, i64, i128, isize / u8, u16, u32, u64, u128, usize i는 부호 있음(signed), u는 부호 없음(unsigned). isize/usize는 플랫폼 포인터 크기와 동일. 부동소수형 (Floating-point) f32, f64 IEEE-754 표준. f64가 기본. 불리언 (Boolean) bool (true / false) 조건식, 제어문에 사용 문자 (Character) char 4바이트 유니코드 스칼라 값(UTF-32). 'a', '한', '\\n' 등
2. 복합 타입 (Compound Types)분류 예시 설명튜플 (Tuple) (i32, f64, char) 서로 다른 타입 묶음. 인덱스로 접근: t.0, t.1 배열 (Array) [i32; 5] 동일 타입 고정 길이. 길이와 타입이 타입 정의에 포함됨. 슬라이스 (Slice) &[T] 배열의 연속된 부분 참조. 길이는 런타임에 결정. 문자열 슬라이스 (String slice) &str UTF-8 문자열의 참조. 리터럴 "hello" 도 &'static str 타입.
3. 사용자 정의 타입- 구조체 (struct)
- rust 복사편집 struct Point { x: i32, y: i32 }
- 열거형 (enum)
- rust 복사편집 enum Direction { North, South, East, West }
- 형식 별칭 (type alias)
- rust 복사편집 type Kilometers = i32;
- 유니언 (union) (unsafe)
- rust 복사편집 union IntOrFloat { i: i32, f: f32 }
4. 특이점- Rust의 모든 변수는 기본적으로 불변(immutable).
- 기본 타입 대부분은 Copy 트레이트를 구현하여 값 복사로 이동.
- 자료형 추론 가능하지만, 모호하면 명시 필요.
- 문자열은 String(가변, heap)과 &str(불변, 참조) 구분 중요.
- Rust는 struct, enum, type alias, union 등으로 타입을 만들 수 있습니다.
- 여러 값을 하나로 묶어 표현하는 타입입니다.
- 하나의 값만 표현하는 타입입니다.
- Rust의 자료형(data types)은 크게 스칼라(Scalar) 타입과 복합(Compound) 타입으로 나뉩니다.
rust 자료형 기본이 불변에 타입 추론이 가능하여 자료형을 안 써도 된다. 다만 상수는 자료형을 명시해야 한다.
match
C++의 switch 문 과 비슷함.
let number = 7;
// if-else
if number < 5 {
println!("less than 5");
} else {
println!("greater or equal to 5");
}
// match (switch 비슷)
match number {
1 => println!("one"),
2 | 3 | 4 => println!("two to four"),
5..=10 => println!("five to ten"),
_ => println!("something else"),
}
반복문
let number = 7;
// if-else
if number < 5 {
println!("less than 5");
} else {
println!("greater or equal to 5");
}
// match (switch 비슷)
match number {
1 => println!("one"),
2 | 3 | 4 => println!("two to four"),
5..=10 => println!("five to ten"),
_ => println!("something else"),
}
Rust match
📌 Rust match와 enum 개념 정리
1. enum과 variant
enum Message {
Quit, // 필드 없음
Move { x: i32, y: i32 }, // 구조체 형태 (필드 있음)
Write(String), // 튜플 형태
}
- Message → 자료형(타입)
- Quit, Move {..}, Write(..) → Message 타입이 가질 수 있는 값의 형태(variant)
- 각 variant는 데이터를 가질 수도 있고 (예: Move, Write), 안 가질 수도 있음 (예: Quit)
2. match 문과 coverage 규칙
- Rust의 match는 모든 가능한 variant를 처리해야 함.
- 일부만 처리하면 컴파일 에러.
- 나머지를 _로 처리하면 C++의 default:와 같은 역할.
match msg {
Message::Quit => { ... }
Message::Move { x, y } => { ... }
Message::Write(text) => { ... }
}
또는 _ 사용:
match msg {
Message::Quit => { ... }
_ => { /* 나머지 전부 처리 */ }
}
3. "Quit"은 자료형이 아님
- Quit은 Message 타입의 하나의 값일 뿐.
- 예:
let m1 = Message::Quit; // 타입: Message
let m2 = Message::Move { x: 5, y: 10 }; // 타입: Message
- 자료형(타입) = Message
- variant = Quit, Move, Write
4. C++와 비교
- C++의 enum은 값만 가지지만,
- Rust enum은 variant마다 데이터를 포함할 수 있음.
- 예:
// C++에서 비슷하게 표현하려면 enum + struct 조합 필요
enum class MessageType { Quit, Move, Write };
struct MoveData { int x, y; };
- Rust의 Message::Move { x, y }는 enum과 구조체의 기능을 한 번에 가짐.
✅ 결론
- 타입: Message
- 값의 형태: Quit, Move {..}, Write(..)
- match: variant에 따라 분기 처리, 모든 경우를 커버해야 함 (_ 사용 가능)
- Rust enum 장점: 각 variant에 개별 데이터 저장 가능 → C++보다 표현력 강력.
rust 범위 확인
#[derive(Debug)]
struct Percentage(u8);
impl Percentage {
fn new(value: u8) -> Option<Self> {
if value <= 100 {
Some(Percentage(value))
} else {
None
}
}
}
fn main() {
let p = Percentage::new(85).unwrap();
println!("{:?}", p); // Percentage(85)
// let p2 = Percentage::new(150).unwrap(); // 런타임에서 panic
}
컴파일 타임에 범위를 못 벗어나게 수정
좋아요. “컴파일 타임에 범위를 못 벗어나게”를 두 가지 층위로 보여줄게요.
- 리터럴처럼 고정된 값은 진짜로 컴파일 에러로 막기
- 런타임에서 오는 값은 동일 타입으로 받되, const 문맥에서는 컴파일 에러, 그 외엔 Result로 안전 처리
impl
Rust에서 **impl**은
“어떤 타입에 대해 메서드나 관련 함수를 구현(implement)하는 블록”
이라고 보면 돼요.
C++에서의 member function 정의 + static method 정의를 합쳐 놓은 개념입니다.
1. 기본 구조
struct Point {
x: i32,
y: i32,
}
// Point 타입에 메서드/함수를 붙인다
impl Point {
// self를 받는 메서드 → 인스턴스에서 호출 가능
fn move_by(&mut self, dx: i32, dy: i32) {
self.x += dx;
self.y += dy;
}
// self를 안 받는 함수 → "연관 함수"(associated function)
fn origin() -> Point {
Point { x: 0, y: 0 }
}
}
사용 예:
fn main() {
let mut p = Point::origin(); // 연관 함수 호출
p.move_by(5, 3); // 메서드 호출
}
2. 특징
- 메서드와 연관 함수 구분
- fn method_name(&self, ...) → 인스턴스에서 호출 (p.method_name())
- fn function_name(...) → 타입에서 호출 (Type::function_name())
- 여러 개의 impl 블록 가능
impl Point { fn length(&self) -> f64 { /* ... */ } } impl Point { fn reset(&mut self) { /* ... */ } } - 큰 타입은 기능별로 나눠서 구현할 수 있습니다.
- 제네릭 / 트레잇과 결합 가능
- impl<T> MyStruct<T> { ... } → 제네릭 타입 구현
- impl MyTrait for MyType { ... } → 트레잇 구현 (다른 의미, 여기선 메서드 정의)
return 타입
Rust에서 함수의 **반환 타입(return type)**은 함수 시그니처에서 -> 뒤에 타입을 적어서 정의합니다.
return 값 또는 return 이 없을 땐 맨 마지막 세미콜론이 없는 표현식 값을 return 한다.
C/C++처럼 앞에 쓰는 게 아니라 함수 매개변수 뒤에 명시하는 방식이에요.
1. 기본 형태
fn add(a: i32, b: i32) -> i32 {
a + b // 세미콜론이 없으면 마지막 표현식이 반환값
}
- -> i32가 반환 타입
- 마지막 줄이 세미콜론 없는 표현식이면 그 값이 반환됨
- 세미콜론을 붙이면 ()(unit type, void 같은 것) 반환
2. return 키워드 사용
fn multiply(a: i32, b: i32) -> i32 {
return a * b; // 조기 반환 가능
}
- Rust에선 보통 마지막 표현식으로 반환하는 걸 선호
- return은 중간에 빠져나올 때 주로 사용
3. 여러 타입 예시
fn get_pi() -> f64 {
3.141592
}
fn is_even(n: i32) -> bool {
n % 2 == 0
}
fn no_return() { // 반환 타입 생략 == -> ()
println!("nothing returned");
}
4. 복합 타입 반환
튜플, 구조체, 제네릭 등도 그대로 -> 뒤에 씁니다.
fn min_max(values: &[i32]) -> (i32, i32) {
let min = *values.iter().min().unwrap();
let max = *values.iter().max().unwrap();
(min, max)
}
struct Point { x: i32, y: i32 }
fn origin() -> Point {
Point { x: 0, y: 0 }
}
5. 제네릭과 트레잇 바운드
fn first<T: Clone>(list: &[T]) -> Option<T> {
list.first().cloned()
}
- T는 제네릭 타입
- 반환 타입은 Option<T>
6. 예외적인 반환: ! (never type)
fn never_return() -> ! {
panic!("This function never returns");
}
- !는 절대 반환하지 않는 함수(무한 루프, 패닉 등)
요약
Rust에서 반환 타입 정의는:
fn function_name(args...) -> ReturnType { ... }
- -> 뒤에 타입을 쓴다
- 마지막 표현식이 암묵적 반환
- ()는 반환값 없음(void 같은 것)
- 제네릭, 튜플, 구조체 등 모든 타입 그대로 작성 가능