Rust 자료형

  • rust에서 기본적으로 제공하는 자료형은 아래와 같다
자료형크기rust 표기
8bit 정수1 bytei8
16bit 정수2 bytei16
32bit 정수4 bytei32
64bit 정수8 bytei64
32bit 실수4 bytef32
64bit 실수8 bytef64
불리언1 bytebool
문자4 bytechar
튜플가변( )
배열가변[ ]
  • 문자열은 std::string::String 내장 모듈로 제공된다
fn main() {
    let number = 30;
    let long_number: i64 = 123456789123456789;

    println!("32bit 정수: {}", number);
    println!("64bit 정수: {}", long_number);
}

overflow

  • 자료형의 범위를 초과하는 경우 overflow가 아닌 panic이 발생한다
    • 디버그 모드에서는 panic, 릴리즈 모드에서는 overflow를 체크하지 않는다
fn main() {
    let mut a: i8 = i8::MAX;
    a = a + 1;
    println!("a = {}", a);
}

tuple

  • tuple은 여러가지 자료형을 담을 수 있다
fn main() {
    let tuple = (1, true, 'a');
    println!("{}, {}, {}", tuple.0, tuple.1, tuple.2);
}

배열

  • 배열에는 한가지 자료형만 선언할 수 있다
  • 배열의 크기는 고정이다
fn main() {
    let arr = [1, 2, 3, 4];

    for num in arr {
        println!("{}", num);
    }
}

buffer overflow

  • rust에서 buffer overflow가 런타임에 발생하게 되면 panic이 발생한다
use std::io;

fn main() {
    let mut arr = [1, 2, 3, 4];

    let mut read = String::new();
    io::stdin().read_line(&mut read).unwrap();
    let index:i32 = read.trim().parse().unwrap();

    println!("arr[{}] = {}", index, arr[index as usize]);
}
  • 이렇게 오류가 발생하였을때 RUST_BACKTRACE 환경변수가 있다면 backtrace를 볼 수 있다
sijin@Sijin:~/hello-world$ RUST_BACKTRACE=1 cargo run

문자열

  • 문자열은 str타입과 String 타입이 있다
  • str 자료형은 기본 자료형으로 불변이다
fn main() {
    let s: &str = "hello world";

    println!("{}", s);

    let slice = &s[0..5];
    println!("{}", slice);

    let upper = s.to_uppercase();
    println!("{}", upper);
}
  • String 자료형은 동적으로 힙 메모리에 저장되는 자료형으로, 문자열 크기를 동적으로 늘리고 줄일 수 있다
fn main() {
    let mut s = String::from("Hello");
    s.push_str("Rust");

    println!("{}", s);
}

불변성

  • 러스트의 모든 변수는 기본적으로 불변성의 성질을 갖는다
    • 불변성은 변수가 생성된 뒤 값을 변경하지 못한다는 의미이다
    • 함수형 언어의 특징 중 하나이다
  • 변수가 불변성을 가지게 되면 병렬 처리에서 race condition이 생기는 경우가 줄어든다
  • 함수에서 함수 바깥의 변수를 변경하는 side effect가 줄어든다
  • 동일한 파라미터에 동일한 값이 return되는 stateless function을 사용하게 된다

섀도잉

fn main() {
    let var = 1;
    println!("var={}", var);
    let var = var + 1;
    println!("var={}", var);
}
  • var에 변경이 필요할 때, var에 mut 키워드를 붙혀 가변 변수로 정의할 수 있다
  • 그러나 가변변수는 최소화하는 것이 좋다
  • mut 대신 위와같이 var를 새로 생성하고 기존 var는 소멸하도록 동작시킬 수 있다
  • 이를 섀도잉이라고 한다

제어문

if

fn main() {
    let cond = true;
    if cond == true {
        println!("True");
    } else {
        println!("False");
    }
}
  • 위 처럼 if를 사용할 수 있다

let-if

fn main() {
    let cond = true;
    let ret = if cond == true {
        String::from("True")
    } else {
        String::from("False")
    };
    println!("{}", ret);
}
  • 위 처럼 if 표현식을 let 구문에서 사용할 수 있다

match

fn main() {
    let var = 1;
    match var {
        1 => println!("1"),
        2 => println!("2"),
        _ => println!("else")
    }
}
  • switch와 비슷하게 match를 사용할 수 있다

let-match

fn main() {
    let var = 1;
    let ret = match var {
        1 => String::from("1"),
        2 => String::from("2"),
        _ => String::from("0")
    };
    println!("{}", ret);
}
  • match도 let 구문에서 사용할 수 있다

반복문

loop

fn main() {
    loop {
        ...
        break;
    }
}
  • loop는 while(true)와 같다
  • break 전까지 무한 반복하고 break를 만나면 탈출한다

for

fn main() {
fn main() {
    let arr = [1, 2, 3, 4];
    for a in arr {
        print!("{}", a);
    }
    for a in 0..5 { // 5회 반복
        print!("{}", a);
    }
}
  • for-in 형식으로 반복문을 사용할 수 있다

while

fn main() {
    let mut cnt = 0;
    while cnt < 5 {
        println!("{}", cnt);
        cnt += 1;
    }
}
  • 조건식과 함께 while을 사용할 수 있다

함수

fn main() {
    println!("{}", add(2, 4));
}

fn add(x: i32, y: i32) -> i32 {
    x + y
}
  • fn 키워드로 함수를 정의할 수 있다

익명함수

fn main() {
    let x= 1;
    let y = 2;
    let sum = {
        x + y
    };
    println!("{}", sum);
}
  • let과 { }를 활용해 익명함수를 만들 수도 있다

클로저

  • 클로저는 주변 범위의 변수를 캡처해 사용할 수 있는 익명 함수이다
  • js의 클로저는 함수가 함수를 return 하는 경우에 만들어졌다
  • rust에서는 || 키워드를 사용해 만들 수 있다고 한다
fn main() {
    let mut x = 5;
    let mut add = |y: i32| {
        x += y;
    };
    
    add(10);
    println!("{}", x);
}

구조체

struct Student {
    id: i32,
    name: String,
    email: String
}

fn create_student(id: i32, name: String, email: String) -> Student {
    Student { id: (id), name: (name), email: (email) }
}
  • 구조체는 c/c++와 매우 비슷하다
  • 구조체 이름은 CamelCase를 사용한다

derive

#[derive(Debug)]
struct Student {
    id: i32,
    name: String,
    email: String
}

fn create_student(id: i32, name: String, email: String) -> Student {
    Student { id: (id), name: (name), email: (email) }
}

fn main() {
    let stu: Student = create_student(1, "name".to_string(), "email".to_string());
    println!("student={:?}", stu);
    // student=Student { id: 1, name: "name", email: "email" }
}
  • struct에 derive Debug 어노테이션을 적용하면 구조체를 쉽게 출력할 수 있다

구조체 메서드

struct Student {
    id: i32,
    name: String,
    email: String
}

impl Student {
    fn greeting(&self) {
        println!("hello my name is {}", self.name);
    }
}

fn create_student(id: i32, name: String, email: String) -> Student {
    Student { id: (id), name: (name), email: (email) }
}

fn main() {
    let stu: Student = create_student(1, "name".to_string(), "email".to_string());
    stu.greeting();
}
  • 구조체 메서드는 구조체 인스턴스와 함께 사용할 수 있다
  • 첫번째 파라미터는 &self 이다

연관함수

struct Student {
    id: i32,
    name: String,
    email: String
}

impl Student {
    fn greeting(&self) {
        println!("hello my name is {}", self.name);
    }

    fn from(id: i32, name: String, email: String) -> Student {
        Student { id: (id), name: (name), email: (email) }
    }
}

fn main() {
    let stu: Student = Student::from(1, "name".to_string(), "email".to_string());
    stu.greeting();
}
  • 연관함수는 static 함수랑 개념이 비슷하다
  • 파라미터에 &self가 없이 선언하면 연관함수가 된다

enum

enum LogLevel {
    Debug,
    Warn,
    Error,
    Fatal
}
  • enum 키워드로 열거형을 정의할 수 있다
enum Message {
    Quit,
    List(i32),
    Put(String),
    Get(i32)
}

impl Message {
    fn execute(&self) {
        match self {
            Message::Quit => println!("Quit"),
            Message::List(val) => println!("List: {}", val),
            Message::Put(val) => println!("Put: {}", val),
            Message::Get(val) => println!("Get: {}", val),
        }
    }
}

fn main() {
    let m = Message::Put(String::from("my message"));
    m.execute();
}
  • 다른 언어의 enum과 달리, enum의 각 열거자에 서로 다른 구조체를 할당할 수 있다

Option 열거형

fn print_optional(val: Option<String>) {
    match val {
        Some(val) => println!("{}", val),
        None => println!("None")
    }
}

fn main() {
    let some_string = Some(String::from("Rust"));
    let none_string = None;

    print_optional(some_string);
    print_optional(none_string);
}
  • Option 열거형은 값이 있을 수도 있고 없을 수도 있는 경우 사용된다
  • Rust에서는 null이 없으므로, 대신 Option 열거형을 사용할 수 있다
  • Some은 값이 있는 경우, None은 없는 경우를 의미한다
  • Option 열거형은 일반적으로 match를 통해 값을 추출한다

test code

#[test]
fn fibo_test() {
    assert_eq!(fibo(6), 8);
    assert_eq!(fibo(7), 13);
}
  • test 어노테이션을 적용해 테스트에서만 동작하는 함수를 선언할 수 있다

0개의 댓글