Rust πŸ¦€

λͺ…이·2023λ…„ 1μ›” 4일
1

Warning μž‘μ„±μ€‘μΈ κΈ€μž…λ‹ˆλ‹€. λ‚΄μš©μ— μˆ˜μ •μ΄ μžˆμ„ 수 μžˆμŠ΅λ‹ˆλ‹€.

Rust 문법 정리

μ™œ Rustλ₯Ό μ“°λŠ”κ°€

Rust만의 λ…νŠΉν•œ νŠΉμ§•λ“€μ΄ μžˆλ‹€.

  • 컴파일 νƒ€μž„ λ©”λͺ¨λ¦¬ μ•ˆμ „
  • μ •μ˜λ˜μ§€ μ•Šμ€ λ™μž‘ μ—†μŒ
  • ν˜„λŒ€ μ–Έμ–΄ κΈ°λŠ₯

컴파일 νƒ€μž„μ— 보μž₯λ˜λŠ” 것듀

  • μ΄ˆκΈ°ν™” λ˜μ§€ μ•Šμ€ λ³€μˆ˜κ°€ μ—†μŒ
  • λ©”λͺ¨λ¦¬ λˆ„μˆ˜κ°€ 거의 μ—†μŒ [1]
  • 더블 프리가 μ—†μŒ [2]
  • Use After Freeκ°€ μ—†μŒ [3]
  • null 포인터가 μ—†μŒ
  • 잊힌 잠긴 Mutexκ°€ μ—†μŒ
  • μ“°λ ˆλ“œκ°„ 데이터 λ ˆμ΄μŠ€κ°€ μ—†μŒ [4]
  • 반볡자 λ¬΄νš¨ν™”κ°€ μ—†μŒ [5]

[1] μ•ˆμ „ν•œ λŸ¬μŠ€νŠΈμ—μ„œ λ©”λͺ¨λ¦¬ λˆ„μˆ˜λ₯Ό μΌμœΌν‚€λŠ” 것은 기술적으둜 κ°€λŠ₯함. Box::leak λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄, μ†Œλ©Έμžλ₯Ό μ‹€ν–‰ν•˜μ§€ μ•Šκ³  μ›μ‹œ μ°Έμ‘°λ₯Ό κ°€μ Έμ˜€κ³ , 이후에 이λ₯Ό μ‚­μ œν•  수 있음. μ•ˆμ „ν•œ λŸ¬μŠ€νŠΈμ—μ„œ λˆ„μˆ˜λ₯Ό λ§Œλ“œλŠ” λ§Žμ€ λ‹€λ₯Έ 방법듀이 μžˆμ§€λ§Œ, "λ©”λͺ¨λ¦¬ λˆ„μˆ˜ μ—†μŒ" 은 "우발적인 λ©”λͺ¨λ¦¬ λˆ„μˆ˜κ°€ 거의 μ—†μŒ" 으둜 이해해야함.
[2] λ©”λͺ¨λ¦¬λ₯Ό λ‘λ²ˆ ν•΄μ œν•˜λŠ” 것
[3] λ©”λͺ¨λ¦¬ freeν•œ 뒀에 μ‚¬μš©ν•˜λŠ” 것
[4] λ©€ν‹° μ“°λ ˆλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” ν™˜κ²½μ—μ„œ 같은 데이터λ₯Ό μ΄μš©ν•˜κ³  λ‹€λ₯Έ μ“°λ ˆλ“œμ—μ„œ 그것을 μ—…λ°μ΄νŠΈν•˜λ©΄ μƒκΈ°λŠ” 일
[5] https://www.geeksforgeeks.org/iterator-invalidation-cpp/ μ°Έκ³ 

λŸ°νƒ€μž„μ— 보μž₯λ˜λŠ” 것듀

μ˜ˆμƒμΉ˜ λͺ»ν•œ λ™μž‘μ΄ μΌμ–΄λ‚˜μ§€ μ•ŠμŒ

  • λ°°μ—΄ 접근은 λ²”μœ„λ₯Ό 확인함
  • μ •μˆ˜ μ˜€λ²„ν”Œλ‘œμš°κ°€ μ •μ˜λ¨

λŸ¬μŠ€νŠΈμ— λ…Ήμ•„λ“  μ΅œμ‹  κΈ°λŠ₯

μ–Έμ–΄ κΈ°λŠ₯

  • μ—΄κ±°ν˜• 및 νŒ¨ν„΄ 맀칭
  • μ œλ„€λ¦­
  • μ˜€λ²„ν—€λ“œ FFIκ°€ μ—†μŒ

도ꡬ

  • μžμ„Έν•œ 컴파일 μ—λŸ¬
  • λ‚΄μž₯ 쒅속성 κ΄€λ¦¬μž
  • ν…ŒμŠ€νŒ… λ‚΄μž₯ 지원

Types

Scalar Types

TypesLiterals
Signed integersi8, i16, i32, i64, i128, isize-10, 0, 1_000, 123i64
Unsigned integersu8, u16, u32, u64, u128, usize0, 123, 10u16
Floating point numbersf32, f643.14, -10.0e20, 2f32
Strings&str"foo", r#"\\"#
Unicode scalar valueschar'a', 'α', '∞'
Byte strings&[u8]b"abc, br#" " " "#
Booleansbooltrue, false

νƒ€μž…λ“€μ˜ λ„ˆλΉ„λŠ” λ‹€μŒκ³Ό κ°™μŒ:

  • iN, uN, 및 fN은 N-bit widthμž„
  • isize와 usizeλŠ” ν¬μΈν„°μ˜ ν¬κΈ°μž„
  • char은 32bit λ„ˆλΉ„
  • bool은 8λΉ„νŠΈ λ„ˆλΉ„

Compound Types

TypesLiterals
Arrays[T; N][20, 30, 40], [0; 3]
Tuples(T1, T2, T3, ...)('x', 1.2, 0)

λ°°μ—΄ μ„ μ–Έ 및 μ ‘κ·Ό

fn main() {
    let mut a: [i8; 10] = [42; 10];
    a[5] = 0;
    println!("a: {:?}", a);
}

νŠœν”Œ μ„ μ–Έ 및 μ ‘κ·Ό

fn main() {
    let t: (i8, bool) = (7, true);
    println!("1st index: {}", t.0);
    println!("2nd index: {}", t.1);
}

Reference

C++κ³Ό 같이, Rustμ—λŠ” μ°Έμ‘°κ°€ 있음.

fn main() {
    let mut x: i32 = 10;
    let ref_x: &mut i32 = &mut x;
    *ref_x = 20;
    println!("x: {x}");
}

C++과의 차이점

  • C 포인터와 λΉ„μŠ·ν•˜κ²Œ ref_xλ₯Ό ν• λ‹Ήν• λ•Œ 역참쑰해야함.
  • RustλŠ” λͺ‡λͺ‡ κ²½μš°μ— μžλ™μœΌλ‘œ μ—­μ°Έμ‘°λ₯Ό 함.

Dangling Reference

RustλŠ” ν—ˆμƒ μ°Έμ‘°λ₯Ό[6] μ •μ μœΌλ‘œ κΈˆμ§€ν•¨.

fn main() {
    let ref_x: &i32;
    {
        let x: i32 = 10;
        ref_x = &x;
    }
    println!("ref_x: {ref_x}");
}
Compiling playground v0.0.1 (/playground)  
error[E0597]: `x` does not live long enough  
--> src/main.rs:5:17  
|  
5 | ref_x = &x;  
| ^^ borrowed value does not live long enough  
6 | }  
| - `x` dropped here while still borrowed  
7 | println!("ref_x: {ref_x}");  
| ----- borrow later used here  
  
For more information about this error, try `rustc --explain E0597`.  
error: could not compile `playground` due to previous error
  • μ°Έμ‘°λŠ” μ°Έμ‘°ν•˜λŠ” 값을 "차용"[7]ν•œλ‹€κ³  함
  • RustλŠ” λͺ¨λ“  참쑰의 수λͺ…을 μΆ”μ ν•˜μ—¬ 수λͺ…이 μΆ©λΆ„νžˆ 긴지 확인함

[6] 포인터가 μ—¬μ „νžˆ ν•΄μ œλœ μ˜μ—­μ„ 가리킀고 μžˆλŠ” 것
[7] λΉŒλ €μ˜¨λ‹€

Slice

μŠ¬λΌμ΄μŠ€λŠ” 더 큰 Collection μ•ˆμ„ λ³Ό 수 있게 ν•΄μ€€λ‹€.

fn main() {
    let a: [i32; 6] = [10, 20, 30, 40, 50, 60];
    println!("a: {a:?}");

    let s: &[i32] = &a[2..4];
    println!("s: {s:?}");
}

μŠ¬λΌμ΄μŠ€λŠ” 슬라이슀된 νƒ€μž…μ—μ„œ 데이터λ₯Ό μ°¨μš©ν•΄μ˜¨λ‹€. κ·Έλ ‡λ‹€λ©΄ a[3]λ₯Ό λ³€κ²½ν•˜λ©΄ μ–΄λ–»κ²Œ 될까? sκ°€ λ°”λ€”κΉŒ? 닡은 λ°”κΏ€ 수 μ—†λ‹€. 일단, λ°°μ—΄ aλŠ” λΆˆλ³€μ΄λ‹€. κ·Έλ ‡λ‹€λ©΄ let mut a: [i32; 6]으둜 μ„ μ–Έν•˜λ©΄ κ°€λŠ₯ν• κΉŒ? λ°°μ—΄ sλŠ” ν˜„μž¬ a의 값을 μ°¨μš©ν•˜κ³  μžˆλ‹€. μš°λ¦¬λŠ” λ‹€λ₯Έ λ³€μˆ˜λ‚˜ ν•¨μˆ˜κ°€ λΉŒλ €κ°„ κ°’μ—λŠ” 값을 ν• λ‹Ήν•  수 μ—†λ‹€.

   Compiling playground v0.0.1 (/playground)
error[E0506]: cannot assign to `a[_]` because it is borrowed
 --> src/main.rs:6:5
  |
5 |     let s: &[i32] = &a[2..4];
  |                      - borrow of `a[_]` occurs here
6 |     a[3] = 90;
  |     ^^^^^^^^^ assignment to borrowed `a[_]` occurs here
7 |     println!("s: {s:?}");
  |                   - borrow later used here

For more information about this error, try `rustc --explain E0506`.
error: could not compile `playground` due to previous error

String vs str

λŸ¬μŠ€νŠΈμ—λŠ” 두가지 λ¬Έμžμ—΄ νƒ€μž…μ΄ μžˆλ‹€: &str, String

fn main() {
    let s1: &str = "Hello";
    println!("s1: {s1}");

    let mut s2: String = String::from("Hello ");
    println!("s2: {s2}");
    s2.push_str(s1);
    println!("s2: {s2}");
}

/*
s1: Hello
s2: Hello 
s2: Hello Hello
*/
  • &str은 λ¬Έμžμ—΄ μŠ¬λΌμ΄μŠ€μ— λŒ€ν•œ λΆˆλ³€ν•œ 참쑰이닀.
  • String은 κ°€λ³€ λ¬Έμžμ—΄ 버퍼이닀.

Function

λ‹€μŒμ€ Fizz BuzzλΌλŠ” κ²Œμž„μ˜ 러슀트 μ½”λ“œμ΄λ‹€.

fn main() {
    fizzbuzz_to(20);   // Defined below, no forward declaration needed
}

fn is_divisible_by(lhs: u32, rhs: u32) -> bool {
    if rhs == 0 {
        return false;  // Corner case, early return
    }
    lhs % rhs == 0     // The last expression is the return value
}

fn fizzbuzz(n: u32) -> () {  // No return value means returning the unit type `()`
    match (is_divisible_by(n, 3), is_divisible_by(n, 5)) {
        (true,  true)  => println!("fizzbuzz"),
        (true,  false) => println!("fizz"),
        (false, true)  => println!("buzz"),
        (false, false) => println!("{n}"),
    }
}

fn fizzbuzz_to(n: u32) {  // `-> ()` is normally omitted
    for n in 1..=n {
        fizzbuzz(n);
    }
}
  • λ°˜ν™˜κ°’μ΄ μ—†λŠ” ν•¨μˆ˜λŠ” ()λ₯Ό λ°˜ν™˜ν•œλ‹€.
  • -> ()λŠ” 쓰지 μ•Šμ•„λ„ λœλ‹€.
  • λŸ¬μŠ€νŠΈμ—μ„œ λ§ˆμ§€λ§‰ ν‘œν˜„μ‹μ€ λ°˜ν™˜κ°’μ΄λ‹€.
  • ν•¨μˆ˜λŠ” μ‚¬μš©ν•˜λŠ” μœ„μΉ˜λ³΄λ‹€ μœ„μ— μ„ μ–Έν•˜μ§€ μ•Šμ•„λ„ λœλ‹€.

Method

λŸ¬μŠ€νŠΈμ—λŠ” λ©”μ„œλ“œκ°€ μžˆλ‹€. 그듀은 νŠΉμ • νƒ€μž…κ³Ό κ΄€λ ¨λœ λ‹¨μˆœν•œ ν•¨μˆ˜μ΄λ‹€. λ©”μ„œλ“œμ˜ 첫 번째 μΈμˆ˜λŠ” λ©”μ„œλ“œμ™€ κ΄€λ ¨λœ νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€μ΄λ‹€.

struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }

    fn inc_width(&mut self, delta: u32) {
        self.width += delta;
    }
}

fn main() {
    let mut rect = Rectangle { width: 10, height: 5 };
    println!("old area: {}", rect.area());
    rect.inc_width(5);
    println!("new area: {}", rect.area());
}

Function Overloading

RustλŠ” μ˜€λ²„λ‘œλ”©μ„ μ§€μ›ν•˜μ§€ μ•ŠλŠ”λ‹€.

  • 각각의 ν•¨μˆ˜λŠ” ν•˜λ‚˜μ˜ κ΅¬ν˜„μ„ 가진닀:
    • 항상 κ³ μ •λœ 수의 맀개 λ³€μˆ˜λ₯Ό 가진닀.
    • 항상 단일 λ§€κ°œλ³€μˆ˜ νƒ€μž… μ„ΈνŠΈλ₯Ό μ‚¬μš©ν•œλ‹€.
  • Default ValueλŠ” μ§€μ›λ˜μ§€ μ•ŠλŠ”λ‹€.
    • λͺ¨λ“  ν˜ΈμΆœλΆ€μ—λŠ” λ™μΌν•œ 수의 μΈμˆ˜κ°€ μžˆλ‹€.
    • λ§€ν¬λ‘œλŠ” λ•Œλ•Œλ‘œ λŒ€μ•ˆμœΌλ‘œ μ‚¬μš©λœλ‹€.

ν•˜μ§€λ§Œ, ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜λŠ” μ œλ„€λ¦­μΌ 수 μžˆλ‹€.

fn pick_one<T>(a: T, b: T) -> T {
    if std::process::id() % 2 == 0 { a } else { b }
}

fn main() {
    println!("coin toss: {}", pick_one("heads", "tails"));
    println!("cash prize: {}", pick_one(500, 1000));
}

Implicit Conversions

RustλŠ” νƒ€μž…κ°„ μ•”μ‹œμ  λ³€ν™˜μ„ μžλ™μœΌλ‘œ μ μš©ν•˜μ§€ μ•ŠλŠ”λ‹€. 그렇기에 λ‹€μŒκ³Ό 같은 ν”„λ‘œκ·Έλž¨μ€ μž‘λ™ν•˜μ§€ μ•ŠλŠ”λ‹€.

fn multiply(x: i16, y: i16) -> i16 {
    x * y
}

fn main() {
    let x: i8 = 15;
    let y: i16 = 1000;

    println!("{x} * {y} = {}", multiply(x, y)); // error
}

Rust의 μ •μˆ˜ νƒ€μž…λ“€μ€ λͺ¨λ‘ From<T>와 Into<T> trait을 κ΅¬ν˜„ν•˜μ—¬ μš°λ¦¬κ°€ 그듀간에 λ³€ν™˜μ„ ν•  수 있게 λ„μš΄λ‹€. From<T> trait은 from() λ©”μ„œλ“œλ₯Ό κ°–κ³  있고, 이와 λΉ„μŠ·ν•˜κ²Œ Into<T> trait은 into() λ©”μ„œλ“œλ₯Ό 가지고 μžˆλ‹€. μ΄λŸ¬ν•œ trait듀을 κ΅¬ν˜„ν•˜λŠ” 것은 μ–΄λ–»κ²Œ νƒ€μž…λ“€μ΄ 그듀이 λ‹€λ₯Έ νƒ€μž…λ“€λ‘œ λ³€ν™˜λ  수 μžˆλŠ”μ§€ 보여쀀닀.

ν‘œμ€€ λΌμ΄λΈŒλŸ¬λ¦¬μ—λŠ” From<i8> for i16에 λŒ€ν•œ κ΅¬ν˜„μ΄ μžˆλ‹€. μ΄λŠ” i8 νƒ€μž…μ„ 가진 λ³€μˆ˜ xλ₯Ό i16::from(x)λ₯Ό ν˜ΈμΆœν•¨μœΌλ‘œμ„œ λ³€μˆ˜ xλ₯Ό i16으둜 λ³€ν™˜ν•  수 μžˆμŒμ„ μ˜λ―Έν•œλ‹€. μ•„λ‹ˆλ©΄, κ°„λ‹¨ν•˜κ²Œ x.into()λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€. μ™œλƒν•˜λ©΄ From<i8> for i16 κ΅¬ν˜„μ΄ μžλ™μ μœΌλ‘œ Into<i16> for i8 κ΅¬ν˜„μ„ λ§Œλ“€κΈ° λ•Œλ¬Έμ΄λ‹€.

이제 μœ„μ˜ μ½”λ“œλ₯Ό μ œλŒ€λ‘œ λ™μž‘ν•˜κ²Œ λ§Œλ“€μ–΄λ³΄μž.

fn multiply(x: i16, y: i16) -> i16 {
    x * y
}

fn main() {
    let x: i8 = 15;
    let y: i16 = 1000;

    println!("{x} * {y} = {}", multiply(x.into(), y));
}

λ§Œμ•½ λ³€ν™˜μ„ μ›ν•˜λŠ” νƒ€μž…μ΄ λ³€ν™˜μ΄ μ§€μ›λ˜λŠ”μ§€ ν™•μΈν•˜λ €λ©΄, ν‘œμ€€ 라이브러리 λ¬Έμ„œμ—μ„œ From<T>κ°€ κ΅¬ν˜„λ˜μ–΄ μžˆλŠ”μ§€λ₯Ό ν™•μΈν•˜λ©΄ λœλ‹€.

Arrays and for Loops

μš°λ¦¬λŠ” 배열이 λ‹€μŒκ³Ό 같이 μ„ μ–Έλœλ‹€λŠ”κ²ƒμ„ λ°°μ› λ‹€.

let array = [10, 20, 30];

μš°λ¦¬λŠ” μœ„μ™€ 같은 배열을 {:?} 디버그 ν‘œν˜„μ„ μ΄μš©ν•˜μ—¬ 좜λ ₯ν•  수 μžˆλ‹€.

fn main() {
    let array = [10, 20, 30];
    println!("array: {array:?}"); // array: [10, 20, 30]
}

RustλŠ” μš°λ¦¬κ°€ for ν‚€μ›Œλ“œλ₯Ό μ΄μš©ν•΄ λ°°μ—΄μ΄λ‚˜ λ²”μœ„μ™€ 같은 것듀을 μˆœνšŒν•  수 있게 ν•΄μ€€λ‹€.

fn main() {
    let array = [10, 20, 30];
    print!("Iterating over array:");
    for n in array {
        print!(" {n}");
    }
    println!();

    print!("Iterating over range:");
    for i in 0..3 {
        print!(" {}", array[i]);
    }
    println!();
}

κ·Έλ ‡λ‹€λ©΄ 배열을 예쁘게 좜λ ₯ν•˜λŠ” ν•¨μˆ˜ pretty_printλ₯Ό λ§Œλ“€κ³  이λ₯Ό μ΄μš©ν•΄μ„œ matrixλ₯Ό transposeν•˜λŠ” ν•¨μˆ˜λ₯Ό μž‘μ„±ν•΄λ³΄μž! (rowμ—μ„œ column으둜)

fn transpose(matrix: [[i32; 3]; 3]) -> [[i32; 3]; 3] {
    let mut new_matrix: [[i32;3];3] = [[0;3];3];
    for i in 0..3 {
        for x in 0..3 {
            new_matrix[i][x] = matrix[x][i];
        }
    }
    return new_matrix;
}

fn pretty_print(matrix: &[[i32; 3]; 3]) {
    for i in 0..3 {
        println!("{:?}", matrix[i]);
    }
}

fn main() {
    let matrix = [
        [101, 102, 103], // <-- the comment makes rustfmt add a newline
        [201, 202, 203],
        [301, 302, 303],
    ];

    println!("matrix:");
    pretty_print(&matrix);

    let transposed = transpose(matrix);
    println!("transposed:");
    pretty_print(&transposed);
}

Variables

RustλŠ” Type Safetyλ₯Ό 정적 타이핑을 톡해 μ œκ³΅ν•œλ‹€. λ³€μˆ˜λŠ” 기본적으둜 λΆˆλ³€μœΌλ‘œ μ„ μ–Έλœλ‹€.

fn main() {
    let x: i32 = 10;
    println!("x: {x}");
    // x = 20; (error)
    // println!("x: {x}");
}

Type Inference

λŸ¬μŠ€νŠΈλŠ” λ³€μˆ˜μ˜ νƒ€μž…μ„ μΆ”λ‘ ν•œλ‹€.

fn takes_u32(x: u32) {
    println!("u32: {x}");
}

fn takes_i8(y: i8) {
    println!("i8: {y}");
}

fn main() {
    let x = 10;
    let y = 20;

    takes_u32(x);
    takes_i8(y);
    // takes_u32(y);
}

러슀트 μ»΄νŒŒμΌλŸ¬κ°€ λ³€μˆ˜μ˜ νƒ€μž…μ„ μΆ”λ‘ ν•˜λŠ” 법
μ•„λž˜ μ½”λ“œλŠ” _λ₯Ό placeholder둜 μ‚¬μš©ν•˜μ—¬ ν¬ν•¨λœ νƒ€μž…μ„ λͺ…μ‹œμ μœΌλ‘œ μ§€μ •ν•˜λŠ” μ½”λ“œ 없이 νŠΉμ • 일반 μ»¨ν…Œμ΄λ„ˆμ— λ³΅μ‚¬ν•˜λ„λ‘ μ»΄νŒŒμΌλŸ¬μ—κ²Œ μ§€μ‹œν•œλ‹€.

fn main() {
    let mut v = Vec::new();
    v.push((10, false));
    v.push((20, true));
    println!("v: {v:?}");

    let vv = v.iter().collect::<std::collections::HashSet<_>>();
    println!("vv: {vv:?}");
 }

collectλŠ” HashSet이 κ΅¬ν˜„ν•˜λŠ” FromIterator에 μ˜μ‘΄ν•œλ‹€.

Static and Constant Variables

μ „μ—­ μƒνƒœλŠ” 정적 및 μƒμˆ˜ λ³€μˆ˜λ“€μ— μ˜ν•΄ κ΄€λ¦¬λœλ‹€.

const

const ν‚€μ›Œλ“œλ₯Ό 톡해 컴파일 νƒ€μž„ μƒμˆ˜λ₯Ό μ„ μ–Έν•  수 μžˆλ‹€.

const DIGEST_SIZE: usize = 3;
const ZERO: Option<u8> = Some(42);

fn compute_digest(text: &str) -> [u8; DIGEST_SIZE] {
   let mut digest = [ZERO.unwrap_or(0); DIGEST_SIZE];
   for (idx, &b) in text.as_bytes().iter().enumerate() {
       digest[idx % DIGEST_SIZE] = digest[idx % DIGEST_SIZE].wrapping_add(b);
   }
   digest
}

fn main() {
   let digest = compute_digest("Hello");
   println!("Digest: {digest:?}");
}

Rust RFC Book에 λ”°λ₯΄λ©΄ 이듀은 μ‚¬μš©μ‹œ μΈλΌμΈλœλ‹€.

static

static ν‚€μ›Œλ“œλ₯Ό 톡해 정적 λ³€μˆ˜λ₯Ό μ„ μ–Έν•  수 μžˆλ‹€.

static BANNER: &str = "Welcome to RustOS 3.14";

fn main() {
    println!("{BANNER}");
}

Rust RFC Book의 λ…ΈνŠΈμ— λ”°λ₯΄λ©΄, 이듀은 μ‚¬μš©μ‹œ 인라인 λ˜μ§€ μ•Šκ³  μ‹€μ œ μ—°κ²°λœ λ©”λͺ¨λ¦¬ μœ„μΉ˜λ₯Ό 가진닀. μ΄λŠ” μ•ˆμ „ν•˜μ§€ μ•Šμ€ μž„λ² λ””λ“œ μ½”λ“œμ— μœ μš©ν•˜λ©° staticν•œ 수λͺ…이 μžˆλ‹€.

  • constλŠ” 의미둠적으둜 C++의 constexpr와 λΉ„μŠ·ν•˜λ‹€.
  • λ°˜λ©΄μ— static은 C++의 constλ‚˜ κ°€λ³€ μ „μ—­ λ³€μˆ˜λ“€κ³Ό 더 λΉ„μŠ·ν•˜λ‹€.
  • λŸ°νƒ€μž„ 평가 μƒμˆ˜κ°€ ν•„μš”ν•œ κ²½μš°κ°€ ν”ν•˜μ§€λŠ” μ•Šμ§€λ§Œ 정적을 μ‚¬μš©ν•˜λŠ” 것보닀 μœ μš©ν•˜κ³  μ•ˆμ „ν•˜λ‹€.

Scopes and Shadowing

λ°”κΉ₯ μŠ€μ½”ν”„μ— μžˆλŠ” λ³€μˆ˜κ°€ 같은 μŠ€μ½”ν”„μ— μžˆλŠ” λ³€μˆ˜λ₯Ό μ‰λ„μž‰ ν•  수 μžˆλ‹€.

fn main() {
    let a = 10;
    println!("before: {a}");

    {
        let a = "hello";
        println!("inner scope: {a}");

        let a = true;
        println!("shadowed in inner scope: {a}");
    }

    println!("after: {a}");
}
  • μ‰λ„μž‰μ€ λͺ¨ν˜Έν•΄λ³΄μ΄μ§€λ§Œ, .unwrap() 뒀에 값을 μœ μ§€ν•˜λŠ”λ° νŽΈλ¦¬ν•˜λ‹€.
  • λ‹€μŒ μ½”λ“œλŠ” νƒ€μž…μ΄ λ³€κ²½λ˜μ§€ μ•ŠλŠ” κ²½μš°μ—λ„ μŠ€μ½”ν”„μ—μ„œ λΆˆλ³€ λ³€μˆ˜λ₯Ό 숨길 λ•Œ μ»΄νŒŒμΌλŸ¬κ°€ λ‹¨μˆœνžˆ λ©”λͺ¨λ¦¬ μœ„μΉ˜λ₯Ό μž¬μ‚¬μš©ν•  수 μ—†λŠ” 이유λ₯Ό 보여쀀닀.
fn main() {
    let a = 1;
    let b = &a;
    let a = a + 1;
    println!("{a} {b}");
}

Memory Management

μ „ν†΅μ μœΌλ‘œ, 언어듀은 λ‘κ°œμ˜ 큰 λ²”μ£Όλ‘œ λ‚˜λ‰œλ‹€.

  • μˆ˜λ™ λ©”λͺ¨λ¦¬ 관리λ₯Ό ν†΅ν•œ 전체 μ œμ–΄: C, C++, Pascal, ...
  • λŸ°νƒ€μž„μ‹œ μžλ™ λ©”λͺ¨λ¦¬ 관리λ₯Ό ν†΅ν•œ μ™„λ²½ν•œ μ•ˆμ „μ„±: Java, Python, Go, Haskel, ...

RustλŠ” λ‹€μŒκ³Ό 같은 μƒˆλ‘œμš΄ 쑰합을 μ œκ³΅ν•œλ‹€.

μ˜¬λ°”λ₯Έ λ©”λͺ¨λ¦¬ κ΄€λ¦¬μ˜ 컴파일 μ‹œκ°„ μ μš©μ„ ν†΅ν•œ μ™„λ²½ν•œ μ œμ–΄ 및 μ•ˆμ „μ„±

λͺ…μ‹œμ μΈ μ†Œμœ κΆŒ κ°œλ…μ„ μ‚¬μš©ν•˜μ—¬ 이λ₯Ό μˆ˜ν–‰ν•œλ‹€.
λ¨Όμ € λ©”λͺ¨λ¦¬ 관리가 μž‘λ™ν•˜λŠ” 방식을 λ‹€μ‹œ μ‚΄νŽ΄λ³΄μž.

The Stack vs The Heap

  • μŠ€νƒ: 지역 λ³€μˆ˜λ₯Ό μœ„ν•œ 연속적인 λ©”λͺ¨λ¦¬ μ˜μ—­

    • 값은 컴파일 νƒ€μž„μ— μ•Œλ €μ§„ κ³ μ • 크기λ₯Ό 가짐
    • 맀우 빠름: μŠ€νƒ 포인터λ₯Ό μ΄λ™ν•˜κΈ°λ§Œ ν•˜λ©΄ 됨
    • κ΄€λ¦¬ν•˜κΈ° 쉬움: ν•¨μˆ˜ ν˜ΈμΆœμ„ λ”°λ₯Έλ‹€
    • ν›Œλ₯­ν•œ λ©”λͺ¨λ¦¬ 지역성
  • νž™: ν•¨μˆ˜ 호좜 μ™ΈλΆ€μ˜ κ°’ μ €μž₯

    • κ°’μ—λŠ” λŸ°νƒ€μž„ μ‹œ κ²°μ •λ˜λŠ” 동적 크기가 있음
    • μŠ€νƒλ³΄λ‹€ μ•½κ°„ 느림. μ•½κ°„μ˜ λΆ€κΈ°(book-keeping)이 ν•„μš”ν•¨
    • λ©”λͺ¨λ¦¬ 지역성을 보μž₯ν•˜μ§€ μ•ŠμŒ

Stack Memory

String을 μƒμ„±ν•˜λŠ” 것은 κ³ μ •λœ 크기의 데이터λ₯Ό stack에 λ„£κ³  λ‹€μ΄λ‚˜λ―Ήν•œ 크기의 데이터λ₯Ό heap에 λ„£λŠ”λ‹€.

fn main() {
    let s1 = String::from("Hello");
}
 Stack                             Heap
.- - - - - - - - - - - - - -.     .- - - - - - - - - - - - - - - -.
:                           :     :                               :
:    s1                     :     :                               :
:   +-----------+-------+   :     :   +----+----+----+----+----+  :
:   | ptr       |   o---+---+-----+-->| H  | e  | l  | l  | o  |  :
:   | len       |     5 |   :     :   +----+----+----+----+----+  :
:   | capacity  |     5 |   :     :                               :
:   +-----------+-------+   :     :                               :
:                           :     `- - - - - - - - - - - - - - - -'
`- - - - - - - - - - - - - -' 
  • String은 Vec에 μ˜ν•΄μ„œ μ§€μ›λ˜λ―€λ‘œ, μš©λŸ‰κ³Ό 길이가 있으며 νž™μ˜ μž¬ν• λ‹Ήμ„ 톡해 λ³€κ²½ κ°€λŠ₯ν•œ 경우 컀질 수 μžˆλ‹€.

Manual Memory Management

Heap λ©”λͺ¨λ¦¬λ₯Ό 직접 ν• λ‹Ή 및 ν• λ‹Ή ν•΄μ œ ν•  수 μžˆλ‹€.
μ£Όμ˜ν•΄μ„œ μˆ˜ν–‰ν•˜μ§€ μ•ŠμœΌλ©΄ 좩돌, 버그, λ³΄μ•ˆ μ·¨μ•½μ„± 및 λ©”λͺ¨λ¦¬ λˆ„μˆ˜κ°€ λ°œμƒν•  수 μžˆλ‹€.

C Example

malloc으둜 ν• λ‹Ήν•œ λͺ¨λ“  포인터λ₯Ό freeν•΄μ€˜μ•Ό ν•œλ‹€.

void foo(size_t n) {
    int* int_array = (int*)malloc(n * sizeof(int));
    //
    // ... lots of code
    //
    free(int_array);
}

ν•¨μˆ˜κ°€ mallocκ³Ό free 사이에 일찍 λ°˜ν™˜λ  경우, 포인터가 μœ μ‹€λ˜λ©°, λ©”λͺ¨λ¦¬λ₯Ό ν•΄μ œν•  수 μ—†κΈ° λ•Œλ¬Έμ— λ©”λͺ¨λ¦¬ λˆ„μˆ˜κ°€ λ°œμƒλœλ‹€.

Ownership

λͺ¨λ“  λ³€μˆ˜ λ°”μΈλ”©μ—λŠ” μœ νš¨ν•œ λ²”μœ„κ°€ 있으며 ν•΄λ‹Ή λ²”μœ„ λ°–μ—μ„œ λ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ 였λ₯˜κ°€ λ‚œλ‹€.

struct Point(i32, i32);

fn main() {
    {
        let p = Point(3, 4);
        println!("x: {}", p.0);
    }
    println!("y: {}", p.1);
}

Rustμ—μ„œλŠ” λ³€μˆ˜κ°€ 값을 μ†Œμœ ν•œλ‹€κ³  λ§ν•œλ‹€. λͺ¨λ“  Rust κ°’μ—λŠ” 항상 μ •ν™•νžˆ ν•˜λ‚˜μ˜ μ†Œμœ μžκ°€ μžˆλ‹€.

μŠ€μ½”ν”„κ°€ λλ‚˜λ©΄ λ³€μˆ˜λŠ” μ‚­μ œλ˜κ³  λ°μ΄ν„°λŠ” ν•΄μ œλœλ‹€. μ—¬κΈ°μ„œ μ†Œλ©Έμž(destructor)λ₯Ό μ‹€ν–‰ν•˜μ—¬ λ¦¬μ†ŒμŠ€λ₯Ό 확보할 수 μžˆλ‹€.

Assignment

할당은 λ³€μˆ˜κ°„μ˜ μ†Œμœ κΆŒ 이전을 λ§ν•œλ‹€.

fn main() {
    let s1: String = String::from("Hello!");
    let s2: String = s1;
    println!("s2: {s2}");
    // println!("s1: {s1}");
}
  • s1 λ³€μˆ˜μ—μ„œ s2 λ³€μˆ˜λ‘œμ˜ 할당은 μ†Œμœ κΆŒμ„ μ΄μ „μ•ˆλ‹€.
  • s1이 μŠ€μ½”ν”„ λ°–μœΌλ‘œ λ‚˜κ°ˆλ•Œ, 아무것도 μΌμ–΄λ‚˜μ§€ μ•ŠλŠ”λ‹€. (아무것도 μ†Œμœ ν•˜κ³  μžˆμ§€ μ•ŠμŒ)
  • s2κ°€ μŠ€μ½”ν”„ λ°–μœΌλ‘œ λ‚˜κ°ˆλ•Œ, λ¬Έμžμ—΄ λ°μ΄ν„°λŠ” ν•΄μ œλœλ‹€.

ν•¨μˆ˜μ— 값을 μ „λ‹¬ν• λ•Œ, κ·Έ 값은 ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜μ— ν• λ‹Ήλœλ‹€. 이것은 μ†Œμœ κΆŒμ„ μ΄μ „ν•œλ‹€.

Clone

무언가λ₯Ό λ³΅μ‚¬ν•˜κ³  μ‹Άμ„λ•Œ, Clone traitλ₯Ό μ΄μš©ν•˜λ©΄ λœλ‹€.

#[derive(Default)]
struct Backends {
    hostnames: Vec<String>,
    weights: Vec<f64>,
}

impl Backends {
    fn set_hostnames(&mut self, hostnames: &Vec<String>) {
        self.hostnames = hostnames.clone();
        self.weights = hostnames.iter().map(|_| 1.0).collect();
    }
}

Copy Types

λ³€μˆ˜ ν• λ‹Ήμ‹œ μ†Œμœ κΆŒ 이전이 κΈ°λ³Έμ΄μ§€λ§Œ, λͺ‡λͺ‡ νƒ€μž…λ“€μ€ 기본적으둜 λ³΅μ œλœλ‹€.

fn main() {
    let x = 42;
    let y = x;
    println!("x: {x}"); // would not be accessible if not Copy
    println!("y: {y}");
}

μ΄λŸ¬ν•œ νƒ€μž…λ“€μ€ Copy trait을 κ΅¬ν˜„ν•œλ‹€.

#[derive(Copy, Clone, Debug)]
struct Point(i32, i32);

fn main() {
    let p1 = Point(3, 4);
    let p2 = p1;
    println!("p1: {p1:?}");
    println!("p2: {p2:?}");
}
  • ν• λ‹Ή 후에, p1κ³Ό p2 λͺ¨λ‘ μžμ‹ μ˜ 데이터λ₯Ό μ†Œμœ ν•˜κ³  μžˆλ‹€.
  • p1.clone()을 톡해 λͺ…μ‹œμ μœΌλ‘œ 데이터λ₯Ό λ³΅μ œν•  수 μžˆλ‹€.

The Drop Trait

Drop traitλ₯Ό κ΅¬ν˜„ν•˜λŠ” 값듀은 μŠ€μ½”ν”„ λ°–μœΌλ‘œ λ‚˜κ°”μ„ λ•Œ μ‹€ν–‰ν•  μ½”λ“œλ₯Ό μ •ν•  수 μžˆλ‹€.

struct Droppable {
    name: &'static str,
}

impl Drop for Droppable {
    fn drop(&mut self) {
        println!("Dropping {}", self.name);
    }
}

fn main() {
    let a = Droppable { name: "a" };
    {
        let b = Droppable { name: "b" };
        {
            let c = Droppable { name: "c" };
            let d = Droppable { name: "d" };
            println!("Exiting block B");
        }
        println!("Exiting block A");
    }
    drop(a);
    println!("Exiting main");
}

Smart Pointers

Box<T>

BoxλŠ” νž™μ˜ 데이터에 λŒ€ν•œ μ†Œμœ  포인터이닀.

fn main() {
    let five = Box::new(5);
    println!("five: {}", *five);
}

Box<T>λŠ” Deref<Target = T>λ₯Ό κ΅¬ν˜„ν•œλ‹€. μ΄λŠ” 즉 Box<T>μ—μ„œ T의 λ©”μ„œλ“œλ₯Ό 직접 ν˜ΈμΆœν•  수 μžˆλ‹€λŠ” λœ»μ΄λ‹€.

μž¬κ·€ μœ ν˜•, ν˜Ήμ€ 동적 크기의 메이터 μœ ν˜•μ„ Boxλ₯Ό μ‚¬μš©ν•΄μ•Όν•œλ‹€.

#[derive(Debug)]
enum List<T> {
    /// A non-empty list: first element and the rest of the list.
    Element(T, Box<List<T>>),
    /// An empty list.
    Nil,
}

fn main() {
    let list: List<i32> =
        List::Element(1, Box::new(List::Element(2, Box::new(List::Nil))));
    println!("{list:?}");
}

Rc

RcλŠ” μ°Έμ‘° κ³„μ‚°λœ 곡유 포인터이닀.
μ—¬λŸ¬ μœ„μΉ˜μ—μ„œ λ™μΌν•œ 데이터λ₯Ό μ°Έμ‘°ν•΄μ•Ό ν•  λ•Œ 이 방법을 μ‚¬μš©ν•˜λ©΄ λœλ‹€.

use std::rc::Rc;

fn main() {
    let a = Rc::new(10);
    let b = Rc::clone(&a);

    println!("a: {a}");
    println!("b: {b}");
}
  • 닀쀑 μŠ€λ ˆλ“œ μ»¨ν…μŠ€νŠΈμ— μžˆλ‹€λ©΄ Arc와 Mutexλ₯Ό 보면 λœλ‹€.
  • 곡유 포인터λ₯Ό Weak ν¬μΈν„°λ‘œ λ‹€μš΄κ·Έλ ˆμ΄λ“œν•˜μ—¬ μ‚­μ œλ˜λŠ” μ£ΌκΈ°λ₯Ό λ§Œλ“€ 수 μžˆλ‹€.

Trait Objects

Trait ojectsλŠ” 예λ₯Ό λ“€μ–΄ μ»¬λ ‰μ…˜μ—μ„œ λ‹€μ–‘ν•œ μœ ν˜•μ˜ 값을 ν—ˆμš©ν•œλ‹€.

struct Dog {
    name: String,
    age: i8,
}
struct Cat {
    lives: i8,
}

trait Pet {
    fn talk(&self) -> String;
}

impl Pet for Dog {
    fn talk(&self) -> String {
        format!("Woof, my name is {}!", self.name)
    }
}

impl Pet for Cat {
    fn talk(&self) -> String {
        String::from("Miau!")
    }
}

fn main() {
    let pets: Vec<Box<dyn Pet>> = vec![
        Box::new(Cat { lives: 9 }),
        Box::new(Dog { name: String::from("Fido"), age: 5 }),
    ];
    for pet in pets {
        println!("Hello, who are you? {}", pet.talk());
    }
}

References

Google, Comprehensive Rust: https://google.github.io/comprehensive-rust/

profile
tech explorer | https://duge.space/myounJAwobV

0개의 λŒ“κΈ€

κ΄€λ ¨ μ±„μš© 정보