Rust 정리

mohadang·2022년 9월 16일
0

정수형

  • Rust 정수형의 기본 타입은 i32이다
fn main() {
  let my_number = 100;//i32
}
  • 정수형 지정
fn main() {
  let small_number1: u8 = 10;
  let small_number2 = 10u8; // 10u8 = 10 of type u8  
  let small_number3 = 10_u8; // This is easier to read
  let big_number = 100_000_000_i32; // 100 million is easy to read with _  
  let number1 = 0________u8;
  let number2 = 1___6______2____4______i32;
  println!("{small_number1}, {small_number2}, {small_number3}");
  println!("{big_number}");
  println!("{number1}, {number2}");
}


10, 10, 10
100000000
0, 1624

부동 소수점

  • Rust 부동 소수점의 기본 타입은 f64이다
fn main() {
    let my_float = 5.; // f64
}
  • Rust 컴파일러는 사용되는 코드를 확인하고 자동으로 형 변환을 수행 한다.
fn main() {
    let my_float = 5.0; // f64
    let my_other_float = 8.5; // f64
    let third_float = my_float + my_other_float; // 결국 f64
}

fn main() {
    let my_float: f32 = 5.0; // f32 지정
    let my_other_float = 8.5; // 컴파일러가 여기까지 확인하면 f64지만
    
    // 이 연산 코드를 보고 my_other_float를 f32 지정로 지정한다.
    let third_float = my_float + my_other_float; 
}

다른 형과의 연산 불가

fn main() {
  let my_float: f64 = 5.0;
  let my_other_float: f32 = 8.5; 
  let third_float = my_float + my_other_float;
}


에러 발생
4 |   let third_float = my_float + my_other_float;
  |                              ^ no implementation for `f64 + f32`

문자열의 크기와 길이

  • Rust의 문자는 1 ~ 4 byte 크기이다.
fn main() {
    let slice = "Hello!";
    println!("Slice is {} bytes and also {} characters.", slice.len(), slice.chars().count());
    let slice2 = "안녕!";
    println!("Slice2 is {} bytes but only {} characters.", slice2.len(), slice2.chars().count());
}


Slice is 6 bytes and also 6 characters.
Slice2 is 7 bytes but only 3 characters.
  • 따라서 유니콘, 이모지등을 문자형으로 표현 가능
fn main() {
  let first_letter = 'A';
  let space = ' '; // A space inside ' ' is also a char
  let other_language_char = 'Ꮔ'; // Thanks to Unicode, other languages like Cherokee display just fine too
  let cat_face = '😺'; // Emojis are chars too
  println!("{cat_face}");
}

캐스팅

  • as 로 캐스팅 가능하다
fn main() {
  let my_number = 100;
  println!("{}", my_number as u8 as char);
}
  • 단 경우에 따라서 바로 캐스팅 불가능 할 수 있다.
fn main() { // main() is where Rust programs start to run. Code goes inside {} (curly brackets)

    let my_number = 100; // We didn't write a type of integer,
                         // so Rust chooses i32. Rust always
                         // chooses i32 for integers if you don't
                         // tell it to use a different type

    println!("{}", my_number as char); // ⚠️
}

메모리 출력

fn main() {
  let my_val = &10;
  println!("{:p}", my_val);//포인터 출력시 :p 사용 해야함
}

! 가 들어가면 매크로이다

fn main() {
  let my_float = 5.0;
  let my_other_float = 8.5; 
  println!("{}", my_float + my_other_float);
}

함수

  • rust 함수 기본 형태는 튜플을 반환 한다.
fn number() { // 반환 타입을 지정하지 않으면 기본적으로 튜플을 반환한다
}
//fn number() -> () {
//}
fn main() {
  let tup = number();
}
  • rust 함수에서는 return 키워드 생략 가능
fn number() -> i32 {
  //return 8;
  8 // return 키워드, ; 키워드 생략 가능
}
fn main() {
  println!("{}", number());
}
  • 생략시 주의
fn number() -> i32 {
  8;
  // ; 을 넣으면 return이 없다고 판단
  //따라서 기본 반환 값인 튜플을 반환 하려고 시도
}
fn main() {
  println!("{}", number());
}


  |
1 | fn number() -> i32 {
  |    ------      ^^^ expected `i32`, found `()`

스코프

  • Rust에서도 스코프의 유효성은 다른 언어들과 같다
fn main() {
    {
        let my_number = 8; // my_number starts here
                           // my_number ends here!
    }

    println!("Hello, number {}", my_number); // ⚠️ there is no my_number and
                                             // println!() can't find it
}
  • 다만 변수를 초기화 하기 위해 스코프를 사용 하기도 한다
fn main() {
  let my_number = {
    let second_number = 8;
    second_number + 9 // No semicolon, so the code block returns 8 + 9.
                      // It works just like a function
  };

  println!("My number is: {}", my_number);//17
}

디버그 프린트

  • 일반적인 방식으로 출력 했다면 실패 할테지만 디버그 프린트를 하면 디버깅에 필요한 정보를 출력 해준다.
fn number() -> () {
}
fn main() {
  let tup = number();
  // println!("{tup}");
  println!("{tup:?}");
  println!("{:?}", tup);
}

String vs str

  • String : 벡터와 같은 가변적인 데이터를 다루는 타입이다. 문자열을 소유하거나 수정할때 필요

  • str : 메모리 어딘가 가변적인 길이 만큼 저장된 immutable한 UTF-8 바이트 데이터이다. 크기를 알 수 없기에 포인터를 통해서만 처리 가능하다. 이뜻은 str을 사용할때 일반적으로 &str 형태로 사용한다.

  • 요약 : 문자열을 소유해서 수정이 필요할 때에는 String을 사용, 문자열을 오로지 읽는데 사용 하기 위해서는 &str 사용

  • 문자열은 &str(imutable) 타입이 아니기에 변경 불가

fn main() {
  let my_name = "david";//&str
  my_name.push("!");//error
  println!("{my_name}");
}
  • 문자열 변경이 필요하면 mut 타입으로 선언과 함께 to_string이나 String::from 호출 필요
fn main() {
  // let mut my_name = "david".to_string();//String
  let mut my_name = String::from("david");//String
  my_name.push('!');
  println!("{my_name}");
}

capacity

  • 문자열 메모리 버퍼 크기를 capacity를 호출하여 확인 가능하다
fn main() {
  let mut my_name = "david".to_string();
  my_name.push_str("+++");
  println!("{} {}", my_name.len(), my_name.capacity());
  my_name.push_str("+++");
  println!("{} {}", my_name.len(), my_name.capacity());  
}

8 10
11 20
  • 매번 메모리 할당과 복사가 발생 한다는 뜻인데 with_capacity를 호출하여 미리 버퍼 크기를 할당 가능하다.
fn main() {
  let mut my_name = String::with_capacity(24);
  my_name.push_str("+++");
  println!("{} {}", my_name.len(), my_name.capacity());
  my_name.push_str("+++");
  println!("{} {}", my_name.len(), my_name.capacity());  
}

const and static

  • 젼역 변수를 사용할때에는 const나 static을 사용한다.
const HIGH_SCORE: i32 = 20;
static mut LOW_SCORE: i32 = 0;

fn main() {
  unsafe {
    LOW_SCORE = 123;
  }
  println!("{HIGH_SCORE}");
}
  • 일반적으로 const를 사용한다. 하지만 static은 const와 약간의 차이가 있다.
    • const는 인라인 되지 않는다.
    • 인라인 되지 않기에 메모리 주소에 하나의 인스턴스를 유지한다.
    • static은 mut과 함께 수정 가능하다. 단 unsafe 키워드와 함께 수정이 필요하다.
profile
mohadang

0개의 댓글