Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 |
Tags
- kotlin
- function
- pushnamed
- animation
- text
- DART
- 크롤러
- Class
- ML
- texttheme
- 클래스
- set
- List
- python
- Collection
- 파이썬
- package
- 웹크롤러
- Flutter
- crawler
- 다트
- 코틀린
- 플러터
- 함수
- variable
- 콜렉션
- textstyle
- map
- import
- Android
Archives
- Today
- Total
조용한 담장
Rust Common Programming Concepts - Quick Reference 본문
Rust Common Programming Concepts - Quick Reference
공부한 내용을 빠르게 떠올리기 위한 코드 중심 참조 문서

목차
3.1 Variables and Mutability
핵심 개념
- 기본값: 불변(immutable)
- 가변 변수는
mut키워드 필요 - 섀도잉(shadowing)으로 타입 변경 가능
- 상수는
const키워드 사용
불변 변수 (기본)
fn test_immutable() {
let x = 5;
println!("x = {}", x);
// x = 6; // error[E0384]: cannot assign twice to immutable variable
}
가변 변수
fn test_mutable() {
let mut x = 5;
println!("Before: {}", x);
x = 6; // OK
println!("After: {}", x);
// 출력:
// Before: 5
// After: 6
}
섀도잉 (Shadowing)
fn test_shadowing() {
// 1. 같은 타입 섀도잉
let x = 5;
let x = x + 1; // 6
let x = x * 2; // 12
println!("x = {}", x); // 12
// 2. 다른 타입으로 섀도잉 (타입 변환)
let spaces = " ";
let spaces = spaces.len(); // &str -> usize
println!("spaces = {}", spaces); // 3
// 3. mut는 타입 변경 불가
let mut count = " ";
// count = count.len(); // 에러! 타입이 다름
}
섀도잉 스코프
fn test_shadowing_scope() {
let x = 5;
{
let x = x * 2; // 내부 스코프에서만 유효
println!("Inner: x = {}", x); // 10
}
println!("Outer: x = {}", x); // 5
}
상수 (Constants)
// 전역 상수 - 타입 명시 필수
const MAX_POINTS: u32 = 100_000;
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
fn test_constants() {
// 함수 내부 상수
const THRESHOLD: f64 = 0.5;
println!("Max points: {}", MAX_POINTS);
println!("Threshold: {}", THRESHOLD);
// const는 mut 불가
// const mut VALUE: i32 = 10; // 에러
}
실전 팁
mut vs shadowing 선택 기준:
fn practical_examples() {
// mut 사용: 같은 타입의 값을 계속 변경
let mut counter = 0;
for _ in 0..10 {
counter += 1;
}
// shadowing 사용: 타입 변환 파이프라인
let input = " 42 ";
let input = input.trim(); // &str
let input = input.parse::<i32>(); // Result<i32, _>
let input = input.unwrap(); // i32
println!("Parsed: {}", input);
// shadowing 사용: 중간 계산 결과 저장
let width = 10;
let width = width * 2; // 단위 변환
let width = width + 5; // 여백 추가
}
성능 고려사항:
fn performance_consideration() {
// 큰 데이터 구조는 mut가 효율적
let mut large_vec = vec![0; 1_000_000];
for i in 0..large_vec.len() {
large_vec[i] = i; // in-place 수정
}
// 작은 데이터는 불변 + 함수형 스타일도 OK
let small_vec = vec![1, 2, 3];
let doubled = small_vec.iter().map(|x| x * 2).collect::<Vec<_>>();
}
3.1 Variables and Mutability - 테스트 코드(Rust Playground)
Gist
3.2 Data Types
핵심 개념
- 정적 타입 언어 - 컴파일 시 모든 타입 결정
- 타입 추론 지원 (대부분 명시 불필요)
- 스칼라 타입: 정수, 부동소수점, 불리언, 문자
- 복합 타입: 튜플, 배열
정수 타입 (Integer Types)
fn test_integer_types() {
// 부호 있음: i8, i16, i32(기본), i64, i128, isize
let a: i8 = -128; // -128 ~ 127
let b: i32 = 42; // 기본 타입
let c: i64 = 1_000_000; // 언더스코어로 가독성
// 부호 없음: u8, u16, u32, u64, u128, usize
let d: u8 = 255; // 0 ~ 255
let e: u32 = 100_000;
// 아키텍처 의존 타입
let f: isize = 100; // 32bit: i32, 64bit: i64
let g: usize = 100; // 배열 인덱스 등에 사용
// 리터럴 표기법
let decimal = 98_222;
let hex = 0xff; // 255
let octal = 0o77; // 63
let binary = 0b1111_0000; // 240
let byte = b'A'; // u8만 가능, 65
println!("hex: {}, octal: {}, binary: {}, byte: {}",
hex, octal, binary, byte);
}
정수 오버플로우 처리
fn test_overflow() {
let mut x: u8 = 255;
// 디버그 모드: panic
// 릴리즈 모드: 2의 보수 래핑 (0이 됨)
// x = x + 1; // 주의
// 명시적 오버플로우 처리 메서드
// 1. wrapping_* : 항상 래핑
let wrapped = x.wrapping_add(1);
println!("wrapped: {}", wrapped); // 0
// 2. checked_* : Option 반환
match x.checked_add(1) {
Some(val) => println!("OK: {}", val),
None => println!("Overflow detected!"), // 이 경로 실행
}
// 3. saturating_* : 최대/최소값 고정
let saturated = x.saturating_add(1);
println!("saturated: {}", saturated); // 255
// 4. overflowing_* : (결과, 오버플로우 여부) 반환
let (result, overflowed) = x.overflowing_add(1);
println!("result: {}, overflowed: {}", result, overflowed);
// result: 0, overflowed: true
}
부동소수점 (Floating-Point Types)
fn test_floating_point() {
let x = 2.0; // f64 (기본)
let y: f32 = 3.0; // f32
// 연산
let sum = 5.0 + 10.0;
let difference = 95.5 - 4.3;
let product = 4.0 * 30.0;
let quotient = 56.7 / 32.2;
let remainder = 43.0 % 5.0;
// 부동소수점 비교 주의
let a = 0.1 + 0.2;
let b = 0.3;
// a == b // false! (부동소수점 오차)
// 올바른 비교
let epsilon = f64::EPSILON;
if (a - b).abs() < epsilon {
println!("거의 같음");
}
// 특수값
let inf = f64::INFINITY;
let neg_inf = f64::NEG_INFINITY;
let nan = f64::NAN;
println!("Is NaN: {}", nan.is_nan());
println!("Is infinite: {}", inf.is_infinite());
}
불리언 (Boolean Type)
fn test_boolean() {
let t = true;
let f: bool = false;
// 1바이트 크기
println!("Size of bool: {}", std::mem::size_of::<bool>()); // 1
// 논리 연산
let and = t && f;
let or = t || f;
let not = !t;
// 비교 연산 결과
let is_greater = 5 > 3; // true
}
문자 (Character Type)
fn test_char() {
let c = 'z';
let emoji = '😻';
let heart = '❤';
let hangul = '한';
// 4바이트 유니코드 스칼라 값
println!("Size: {}", std::mem::size_of::<char>()); // 4
// 문자열과 다름
let char_literal = 'a'; // char
let str_literal = "a"; // &str
// let wrong = 'ab'; // 에러: 단일 문자만
}
튜플 (Tuple Type)
fn test_tuple() {
// 1. 기본 선언
let tup: (i32, f64, u8) = (500, 6.4, 1);
// 2. 분해 (destructuring)
let (x, y, z) = tup;
println!("x: {}, y: {}, z: {}", x, y, z);
// 3. 인덱스 접근 (점 표기법)
let five_hundred = tup.0;
let six_point_four = tup.1;
let one = tup.2;
// 4. 빈 튜플 = unit 타입
let unit: () = ();
// 5. 단일 요소 튜플
let single = (5,); // 쉼표 필수
// let not_tuple = (5); // 이건 그냥 정수
}
튜플 활용 예제
fn swap(pair: (i32, i32)) -> (i32, i32) {
let (a, b) = pair;
(b, a) // 교환된 튜플 반환
}
fn divide(dividend: i32, divisor: i32) -> (i32, i32) {
(dividend / divisor, dividend % divisor) // (몫, 나머지)
}
fn test_tuple_usage() {
let pair = (5, 10);
let swapped = swap(pair);
println!("Original: {:?}, Swapped: {:?}", pair, swapped);
let (quotient, remainder) = divide(17, 5);
println!("17 / 5 = {} remainder {}", quotient, remainder);
}
배열 (Array Type)
fn test_array() {
// 1. 기본 선언
let a = [1, 2, 3, 4, 5];
let b: [i32; 5] = [1, 2, 3, 4, 5]; // 타입 명시
// 2. 같은 값으로 초기화
let zeros = [0; 5]; // [0, 0, 0, 0, 0]
let threes = [3; 10]; // 10개의 3
// 3. 인덱스 접근
let first = a[0];
let second = a[1];
// 4. 크기 확인
println!("Length: {}", a.len());
// 5. 메모리 크기 (스택 할당)
println!("Size: {} bytes", std::mem::size_of_val(&a));
// i32 * 5 = 20 bytes
}
배열 주의사항
fn test_array_bounds() {
let a = [1, 2, 3, 4, 5];
// 유효한 인덱스
let element = a[2];
println!("Element: {}", element);
// 범위 초과 - 런타임 패닉
// let invalid = a[10]; // thread 'main' panicked
// 안전한 접근
if let Some(&value) = a.get(2) {
println!("Safe access: {}", value);
}
match a.get(10) {
Some(&value) => println!("Found: {}", value),
None => println!("Index out of bounds"),
}
}
배열 반복
fn test_array_iteration() {
let a = [10, 20, 30, 40, 50];
// 1. for 루프로 값 순회
for element in a {
println!("Value: {}", element);
}
// 2. iter()로 참조 순회
for element in a.iter() {
println!("Ref: {}", element);
}
// 3. 인덱스와 값 함께
for (index, &value) in a.iter().enumerate() {
println!("a[{}] = {}", index, value);
}
// 4. 가변 반복 (배열은 고정 크기이므로 드묾)
let mut b = [1, 2, 3];
for element in b.iter_mut() {
*element *= 2;
}
println!("{:?}", b); // [2, 4, 6]
}
배열 vs 벡터
fn test_array_vs_vector() {
// 배열: 고정 크기, 스택, 컴파일 타임 크기 결정
let array: [i32; 5] = [1, 2, 3, 4, 5];
// array.push(6); // 메서드 없음
// 벡터: 동적 크기, 힙, 런타임 크기 변경 가능
let mut vector = vec![1, 2, 3, 4, 5];
vector.push(6); // OK
println!("Vector: {:?}", vector);
// 배열 -> 슬라이스
let slice: &[i32] = &array[1..3];
println!("Slice: {:?}", slice); // [2, 3]
}
타입 변환
fn test_type_conversion() {
// 1. as 키워드 (명시적 캐스팅)
let integer: i32 = 42;
let float = integer as f64;
let byte = integer as u8;
// 2. 문자열 -> 숫자
let num: i32 = "42".parse().unwrap();
let num: i32 = "42".parse::<i32>().unwrap(); // 터보피시
// 3. 숫자 -> 문자열
let s = 42.to_string();
let s = format!("{}", 42);
// 4. From/Into 트레이트
let s = String::from("hello");
let s: String = "hello".into();
// 5. TryFrom (실패 가능한 변환)
use std::convert::TryFrom;
match i32::try_from(300u16) {
Ok(n) => println!("Converted: {}", n),
Err(e) => println!("Conversion failed: {}", e),
}
}
타입 선택 가이드
fn type_selection_guide() {
// 정수 기본: i32 (성능과 범위 균형)
let default_int = 42;
// 배열 인덱스, 크기: usize
let arr = [1, 2, 3, 4, 5];
for i in 0..arr.len() { // len()은 usize 반환
println!("{}", arr[i]);
}
// 바이트 데이터: u8
let bytes: Vec<u8> = vec![0x48, 0x65, 0x6C, 0x6C, 0x6F];
// 고정 크기 필요: 배열
let weekdays: [&str; 7] = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
// 동적 크기 필요: Vec
let mut dynamic_list = Vec::new();
dynamic_list.push(1);
dynamic_list.push(2);
}
3.2 Data Types - 테스트 코드(Rust Playground)
Gist
3.3 Functions
핵심 개념
fn키워드로 정의- snake_case 명명 규칙
- 매개변수는 반드시 타입 명시
- 반환 타입은
->뒤에 명시 - 표현식 기반: 마지막 표현식이 반환값
기본 함수 선언
fn main() {
println!("Hello from main!");
another_function();
function_with_params(5, 10);
}
fn another_function() {
println!("Another function");
}
fn function_with_params(x: i32, y: i32) {
println!("x: {}, y: {}", x, y);
}
함수 반환값
// 1. 표현식으로 반환 (세미콜론 없음)
fn five() -> i32 {
5 // 표현식
}
fn add(a: i32, b: i32) -> i32 {
a + b // 마지막 표현식이 반환값
}
// 2. 명시적 return
fn subtract(a: i32, b: i32) -> i32 {
return a - b; // 일찍 반환할 때 유용
}
// 3. 여러 return 경로
fn abs_difference(a: i32, b: i32) -> i32 {
if a > b {
return a - b; // 일찍 반환
}
b - a // 마지막 표현식
}
fn test_returns() {
assert_eq!(five(), 5);
assert_eq!(add(2, 3), 5);
assert_eq!(subtract(10, 3), 7);
assert_eq!(abs_difference(10, 5), 5);
assert_eq!(abs_difference(5, 10), 5);
}
표현식 vs 문
fn test_expression_vs_statement() {
// 문(Statement): 값을 반환하지 않음
let y = 6; // 값 바인딩은 문
// let x = (let y = 6); // 에러: let은 값이 없음
// 표현식(Expression): 값을 평가
let x = 5; // 5는 표현식
let y = {
let x = 3;
x + 1 // 4를 반환 (세미콜론 없음)
};
println!("y: {}", y); // 4
// 세미콜론이 있으면 ()를 반환
let z = {
let x = 3;
x + 1; // 세미콜론 -> 문
}; // z의 타입은 ()
}
세미콜론의 중요성
// 잘못된 반환
fn wrong_return() -> i32 {
let x = 5;
x + 1; // 세미콜론 때문에 () 반환
// error: mismatched types
}
// 올바른 반환
fn correct_return() -> i32 {
let x = 5;
x + 1 // 세미콜론 없음 -> 표현식
}
// 명시적 return 사용
fn explicit_return() -> i32 {
let x = 5;
return x + 1; // 세미콜론 있어도 OK
}
함수 매개변수 패턴
// 1. 튜플 분해
fn print_coordinates((x, y): (i32, i32)) {
println!("x: {}, y: {}", x, y);
}
// 2. 참조 매개변수
fn calculate_length(s: &String) -> usize {
s.len()
}
// 3. 가변 참조
fn change(s: &mut String) {
s.push_str(", world");
}
fn test_parameters() {
print_coordinates((10, 20));
let s = String::from("hello");
let len = calculate_length(&s);
println!("Length: {}", len);
let mut s = String::from("hello");
change(&mut s);
println!("{}", s); // "hello, world"
}
다중 반환값
// 튜플로 여러 값 반환
fn swap(pair: (i32, i32)) -> (i32, i32) {
let (a, b) = pair;
(b, a)
}
fn divide_with_remainder(dividend: i32, divisor: i32) -> (i32, i32) {
(dividend / divisor, dividend % divisor)
}
fn analyze_number(n: i32) -> (bool, bool, i32) {
let is_positive = n > 0;
let is_even = n % 2 == 0;
let absolute = n.abs();
(is_positive, is_even, absolute)
}
fn test_multiple_returns() {
let (a, b) = swap((1, 2));
println!("Swapped: ({}, {})", a, b);
let (quotient, remainder) = divide_with_remainder(17, 5);
println!("17 / 5 = {} R {}", quotient, remainder);
let (positive, even, abs_val) = analyze_number(-42);
println!("Positive: {}, Even: {}, Abs: {}", positive, even, abs_val);
}
재귀 함수
fn factorial(n: u32) -> u32 {
if n == 0 {
1
} else {
n * factorial(n - 1)
}
}
fn fibonacci(n: u32) -> u32 {
match n {
0 => 0,
1 => 1,
_ => fibonacci(n - 1) + fibonacci(n - 2),
}
}
fn test_recursion() {
println!("5! = {}", factorial(5)); // 120
println!("fib(10) = {}", fibonacci(10)); // 55
}
함수 설계 팁
// 작고 명확한 책임
fn is_even(n: i32) -> bool {
n % 2 == 0
}
fn is_prime(n: u32) -> bool {
if n < 2 { return false; }
for i in 2..=(n as f64).sqrt() as u32 {
if n % i == 0 { return false; }
}
true
}
// 조기 반환으로 가독성 향상
fn process_value(value: Option<i32>) -> i32 {
// None 체크를 먼저
let val = match value {
Some(v) => v,
None => return 0,
};
// 음수 체크
if val < 0 {
return -val;
}
// 일반 케이스
val * 2
}
// 타입 별칭으로 명확성
type Point = (i32, i32);
type Result<T> = std::result::Result<T, String>;
fn distance(p1: Point, p2: Point) -> f64 {
let (x1, y1) = p1;
let (x2, y2) = p2;
(((x2 - x1).pow(2) + (y2 - y1).pow(2)) as f64).sqrt()
}
3.4 Comments
핵심 개념
- 일반 주석:
//(한 줄),/* */(여러 줄) - 문서 주석:
///(외부),//!(내부) - 문서 주석은 Markdown 지원
cargo doc으로 문서 생성
일반 주석
fn test_comments() {
// 한 줄 주석
let x = 5; // 코드 뒤 주석도 가능
/*
* 여러 줄 주석
* 두 번째 줄
*/
let y = 10;
/* 중첩 /* 주석 */ 가능 */
// 코드 주석 처리
// let unused = 42;
}
문서 주석 - 외부
/// 두 수를 더합니다.
///
/// # Examples
///
/// ```
/// let result = add(2, 3);
/// assert_eq!(result, 5);
/// ```
///
/// # Arguments
///
/// * `a` - 첫 번째 숫자
/// * `b` - 두 번째 숫자
///
/// # Returns
///
/// 두 숫자의 합
fn add(a: i32, b: i32) -> i32 {
a + b
}
/// 숫자가 짝수인지 확인합니다.
///
/// # Panics
///
/// 이 함수는 패닉하지 않습니다.
///
/// # Safety
///
/// 이 함수는 안전합니다.
fn is_even(n: i32) -> bool {
n % 2 == 0
}
문서 주석 - 내부
//! 수학 연산을 위한 유틸리티 모듈
//!
//! 이 모듈은 기본적인 수학 연산 함수들을 제공합니다.
//!
//! # Examples
//!
//! ```
//! use my_crate::math;
//! let sum = math::add(2, 3);
//! ```
pub mod math {
//! 수학 함수 모듈
/// 덧셈 수행
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
}
문서 주석 섹션들
/// 복잡한 계산을 수행합니다.
///
/// # Arguments
///
/// * `input` - 입력값
///
/// # Returns
///
/// 계산 결과
///
/// # Examples
///
/// ```
/// let result = complex_calculation(42);
/// assert_eq!(result, 84);
/// ```
///
/// # Panics
///
/// `input`이 음수일 때 패닉합니다.
///
/// # Errors
///
/// 이 함수는 에러를 반환하지 않습니다.
///
/// # Safety
///
/// 이 함수는 unsafe 블록을 포함하지 않습니다.
fn complex_calculation(input: i32) -> i32 {
assert!(input >= 0, "Input must be non-negative");
input * 2
}
주석 작성 팁
// 나쁜 주석: 코드를 그대로 설명
// x에 5를 할당
let x = 5;
// 좋은 주석: 왜 이렇게 했는지 설명
// 성능 최적화를 위해 버퍼 크기를 미리 할당
let mut buffer = Vec::with_capacity(1000);
// 복잡한 로직 설명
// Boyer-Moore 알고리즘을 사용하여 검색 성능 향상
// O(n) -> O(n/m) 복잡도 개선
fn search_pattern(text: &str, pattern: &str) -> Option<usize> {
// implementation
None
}
// TODO, FIXME, HACK 표시
// TODO: 에러 처리 추가 필요
// FIXME: 메모리 누수 가능성
// HACK: 임시 방편, 나중에 리팩토링 필요
3.5 Control Flow
핵심 개념
if,else if,else- 조건 분기loop- 무한 루프while- 조건 루프for- 컬렉션 순회- 모든 제어문이 표현식 (값을 반환할 수 있음)
if 표현식
fn test_if() {
let number = 6;
// 1. 기본 if
if number < 5 {
println!("true");
} else {
println!("false");
}
// 2. else if
if number % 4 == 0 {
println!("divisible by 4");
} else if number % 3 == 0 {
println!("divisible by 3");
} else if number % 2 == 0 {
println!("divisible by 2");
} else {
println!("not divisible by 4, 3, or 2");
}
// 3. if를 표현식으로 사용
let condition = true;
let value = if condition { 5 } else { 6 };
println!("value: {}", value);
// 4. 모든 분기가 같은 타입 반환해야 함
// let wrong = if condition { 5 } else { "six" }; // 에러
}
if를 이용한 패턴
fn test_if_patterns() {
let number = 7;
// 1. 범위 체크
let category = if number < 0 {
"negative"
} else if number == 0 {
"zero"
} else if number < 10 {
"single digit"
} else {
"multiple digits"
};
// 2. 조기 반환
fn check_positive(n: i32) -> Result<i32, String> {
if n <= 0 {
return Err("Not positive".to_string());
}
Ok(n * 2)
}
// 3. if let 패턴 (Option/Result 처리)
let some_value = Some(7);
if let Some(x) = some_value {
println!("Got: {}", x);
}
}
loop - 무한 루프
fn test_loop() {
let mut counter = 0;
// 1. 기본 무한 루프
loop {
counter += 1;
if counter == 5 {
break;
}
}
println!("Counter: {}", counter);
// 2. loop에서 값 반환
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2; // 20 반환
}
};
println!("Result: {}", result);
// 3. 레이블로 중첩 루프 제어
'outer: loop {
println!("Outer loop");
'inner: loop {
println!("Inner loop");
break 'outer; // 외부 루프 탈출
}
println!("This will never print");
}
}
while 루프
fn test_while() {
let mut number = 3;
// 1. 기본 while
while number != 0 {
println!("{}!", number);
number -= 1;
}
println!("LIFTOFF!");
// 2. while let 패턴
let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() {
println!("Popped: {}", top);
}
// 3. 조건이 복잡한 경우
let mut x = 0;
while x < 100 && x * x < 500 {
x += 1;
}
println!("x: {}", x);
}
for 루프
fn test_for() {
let a = [10, 20, 30, 40, 50];
// 1. 배열 순회 (소유권 이동)
for element in a {
println!("Value: {}", element);
}
// 2. 참조로 순회
for element in a.iter() {
println!("Ref: {}", element);
}
// 3. 범위 순회
for i in 0..5 { // 0, 1, 2, 3, 4
println!("{}", i);
}
for i in 0..=5 { // 0, 1, 2, 3, 4, 5 (inclusive)
println!("{}", i);
}
// 4. 역순
for i in (1..4).rev() { // 3, 2, 1
println!("{}!", i);
}
// 5. 인덱스와 값
for (index, value) in a.iter().enumerate() {
println!("a[{}] = {}", index, value);
}
// 6. 가변 반복자
let mut v = vec![1, 2, 3];
for item in v.iter_mut() {
*item *= 2;
}
println!("{:?}", v); // [2, 4, 6]
}
break와 continue
fn test_break_continue() {
// 1. continue - 다음 반복으로
for i in 0..10 {
if i % 2 == 0 {
continue; // 짝수는 건너뛰기
}
println!("Odd: {}", i);
}
// 2. break - 루프 탈출
let mut sum = 0;
for i in 1.. { // 무한 범위
sum += i;
if sum > 100 {
println!("Stopped at i = {}", i);
break;
}
}
// 3. 레이블과 함께 사용
'outer: for x in 0..5 {
for y in 0..5 {
if x * y > 10 {
break 'outer; // 외부 루프 탈출
}
println!("x: {}, y: {}", x, y);
}
}
}
제어 흐름 비교
fn compare_control_flow() {
let data = vec![1, 2, 3, 4, 5];
// 1. 정확한 횟수 반복 -> for
for i in 0..5 {
println!("{}", i);
}
// 2. 조건이 명확 -> while
let mut count = 0;
while count < 5 {
println!("{}", count);
count += 1;
}
// 3. 무한 루프, 중간에 break -> loop
let mut sum = 0;
loop {
sum += 1;
if sum > 100 {
break;
}
}
// 4. 컬렉션 순회 -> for
for item in data.iter() {
println!("{}", item);
}
}
실전 제어 흐름 패턴
// 1. 입력 검증
fn validate_input(value: i32) -> Result<i32, String> {
if value < 0 {
return Err("Value must be non-negative".to_string());
}
if value > 100 {
return Err("Value must be <= 100".to_string());
}
Ok(value)
}
// 2. 재시도 로직
fn retry_with_limit<F>(mut operation: F, max_attempts: u32) -> Result<(), String>
where
F: FnMut() -> Result<(), String>,
{
for attempt in 1..=max_attempts {
match operation() {
Ok(_) => return Ok(()),
Err(e) if attempt == max_attempts => {
return Err(format!("Failed after {} attempts: {}", max_attempts, e));
}
Err(_) => continue,
}
}
unreachable!()
}
// 3. 조기 반환으로 중첩 제거
fn process_data(data: Option<Vec<i32>>) -> i32 {
// 중첩된 if
// if let Some(vec) = data {
// if !vec.is_empty() {
// if vec[0] > 0 {
// return vec[0] * 2;
// }
// }
// }
// 조기 반환
let vec = match data {
Some(v) => v,
None => return 0,
};
if vec.is_empty() {
return 0;
}
if vec[0] <= 0 {
return 0;
}
vec[0] * 2
}
// 4. 상태 머신 패턴
enum State { Start, Processing, Done }
fn state_machine() {
let mut state = State::Start;
let mut count = 0;
loop {
state = match state {
State::Start => {
println!("Starting...");
State::Processing
}
State::Processing => {
count += 1;
println!("Processing... {}", count);
if count >= 3 {
State::Done
} else {
State::Processing
}
}
State::Done => {
println!("Done!");
break;
}
};
}
}
종합 예제
FizzBuzz (다양한 구현)
// 1. if-else 버전
fn fizzbuzz_if(n: u32) {
for i in 1..=n {
if i % 15 == 0 {
println!("FizzBuzz");
} else if i % 3 == 0 {
println!("Fizz");
} else if i % 5 == 0 {
println!("Buzz");
} else {
println!("{}", i);
}
}
}
// 2. match 버전
fn fizzbuzz_match(n: u32) {
for i in 1..=n {
match (i % 3, i % 5) {
(0, 0) => println!("FizzBuzz"),
(0, _) => println!("Fizz"),
(_, 0) => println!("Buzz"),
_ => println!("{}", i),
}
}
}
// 3. 함수형 스타일
fn fizzbuzz_functional(n: u32) {
(1..=n).for_each(|i| {
let output = match (i % 3, i % 5) {
(0, 0) => "FizzBuzz".to_string(),
(0, _) => "Fizz".to_string(),
(_, 0) => "Buzz".to_string(),
_ => i.to_string(),
};
println!("{}", output);
});
}
소수 판별 및 생성
fn is_prime(n: u32) -> bool {
if n <= 1 {
return false;
}
if n <= 3 {
return true;
}
if n % 2 == 0 || n % 3 == 0 {
return false;
}
let mut i = 5;
while i * i <= n {
if n % i == 0 || n % (i + 2) == 0 {
return false;
}
i += 6;
}
true
}
fn primes_up_to(limit: u32) -> Vec<u32> {
(2..=limit).filter(|&n| is_prime(n)).collect()
}
fn nth_prime(n: usize) -> u32 {
let mut count = 0;
let mut num = 2;
loop {
if is_prime(num) {
count += 1;
if count == n {
return num;
}
}
num += 1;
}
}
계산기
fn calculator(a: f64, b: f64, op: char) -> Result<f64, String> {
match op {
'+' => Ok(a + b),
'-' => Ok(a - b),
'*' => Ok(a * b),
'/' => {
if b == 0.0 {
Err("Division by zero".to_string())
} else {
Ok(a / b)
}
}
_ => Err(format!("Unknown operator: {}", op)),
}
}
fn test_calculator() {
let operations = vec![
(10.0, 5.0, '+'),
(10.0, 5.0, '-'),
(10.0, 5.0, '*'),
(10.0, 5.0, '/'),
(10.0, 0.0, '/'),
];
for (a, b, op) in operations {
match calculator(a, b, op) {
Ok(result) => println!("{} {} {} = {}", a, op, b, result),
Err(e) => println!("{} {} {} -> Error: {}", a, op, b, e),
}
}
}
실행 테스트
모든 예제를 실행하는 테스트 파일:
fn main() {
println!("=== 3.1 Variables and Mutability ===");
test_immutable();
test_mutable();
test_shadowing();
test_constants();
println!("\n=== 3.2 Data Types ===");
test_integer_types();
test_overflow();
test_floating_point();
test_tuple();
test_array();
println!("\n=== 3.3 Functions ===");
test_returns();
test_expression_vs_statement();
test_recursion();
println!("\n=== 3.4 Comments ===");
// 주석 테스트는 컴파일만 확인
println!("\n=== 3.5 Control Flow ===");
test_if();
test_loop();
test_while();
test_for();
println!("\n=== Comprehensive Examples ===");
fizzbuzz_match(15);
println!("Is 17 prime? {}", is_prime(17));
println!("Primes up to 20: {:?}", primes_up_to(20));
test_calculator();
}
3.3 Functions & 3.5 Control Flow - 테스트 코드
Gist
참고 자료
Comments
