🤔 Rust? 그게 뭔데
Rust는 컴파일러가 매우 똑똑한 프로그래밍 언어에요.
지난 해 C언어를 다시 배워보면서 C의 포인터 등이 강력하긴 했지만 별로 마음에 들지 않았던 차에, Rust 얘기를 좀 들어보니 배워보고 싶어지더라고요.
이번에 개강이기도 하니, 이참에 뭐 하나 새로 배워보자! 하고 도전해봤습니다.
간단하게 기본 문법들을 짚어보며 배운 내용들을 조금씩 정리해볼게요.
Rust에서 변수 선언은 let
키워드를 사용해요. 변수의 타입은 변수명 뒤에 :타입
형태로 작성해요. 이렇게 선언된 변수들은 기본적으로 불변이에요.
let x: i32 = 1;
let y: f64 = 3.14;
변수의 값을 변경할 수 있는, 가변변수로 만들기 위해서는 mut
키워드를 함께 사용해야 해요.
let mut z: i32 = 42;
z = 32;
Rust는 정적 타입 언어이자 강타입 언어로, 모든 타입 검사가 컴파일 시점에 이루어진다고 해요. 동시에 타입 추론을 지원해서, 변수의 타입 선언은 생략될 수 있어요.
let x = 1; // 정수 값은 기본적으로 i32로 타입 추론됩니다.
let y = 3.14; // 실수 값은 기본적으로 f64로 타입 추론됩니다.
앞서, let
만 사용해 선언한 변수는 불변이라고 했어요. 하지만 변수 자체를 다시 선언해서 값을 바꿀 수는 있어요. 이를 섀도잉이라고 해요.
let x = "42";
let x = 1;
println!("{}", x); // 이후에 선언된 x의 값인 1이 출력돼요.
모든 타입을 소개하진 못하고, 기본적인 타입들 몇가지를 소개할게요.
타입 | 설명 |
---|---|
i8 | 8비트 정수 |
i16 | 16비트 정수 |
i32 | 32비트 정수 |
i64 | 64비트 정수 |
i128 | 128비트 정수 |
isize | 아키텍처 |
u8 | 부호 없는 8비트 정수 |
u16 | 부호 없는 16비트 정수 |
u32 | 부호 없는 32비트 정수 |
u64 | 부호 없는 64비트 정수 |
u128 | 부호 없는 128비트 정수 |
usize | 부호 없는 아키텍처 |
f32 | 32비트 부동소수점 실수 |
f64 | 64비트 부동소수점 실수 |
bool | 불리언(boolean) |
String | 문자열 |
str | 문자열 슬라이스 |
💡
isize
,usize
는 컴퓨터 아키텍처가 32비트인지 64비트인지에 따라 크기가 달라지는 기본 포인터 크기에요.
🔎 String과 str이 뭐가 다른걸까요?
Rust에서 타입 캐스팅을 할 때는 as
키워드를 사용해요.
let f = 3.14;
let i = f as i32;
println!("{} -> {}", f, i); // 3.14 -> 3
상수를 선언하는 키워드가 따로 있어요. 몇몇은 익숙할 것 같은, const
키워드에요. Rust의 작명 규칙에 따르면, 상수는 SCREAMINGSNAKE_CASE (모두 대문자로 쓰고, 단어 구분은 언더바(``)로 하는 방식이에요.) 로 작성해요.
const PI: f64 = 3.14;
🔎
let
으로 선언한 변수도 이미 불변인데, 굳이const
로 상수를 선언하는 이유는 뭘까요?
러스트에서 함수는 fn
키워드로 선언해요.
fn hello() {
println!("Hello World!");
}
인자와 반환값을 가질 경우, 인자와 반환값 모두 타입을 선언해줘야 해요.
fn add(num1: i32, num2: i32) -> i32 {
return num1 + num2;
}
Rust는 함수의 코드 마지막에서 return
문을 생략할 수 있어요. 이 때, 세미콜론이 없다는 점에 주의하세요.
fn add(num1: i32, num2: i32) -> i32 {
num1 + num2
}
함수 호출은 아래와 같이 해요.
fn main() {
let res = add(1, 2);
println!("1 + 2 = {}", res);
}
Rust의 함수에서 둘 이상의 값을 반환할 때는, 값을 튜플로 묶어 반환할 수 있어요.
fn swap(num1: i32, num2: i32) -> (i32, i32) {
(num2, num1)
}
fn main() {
let mut x = 1;
let mut y = 2;
println!("x = {}, y = {}", x, y); // x = 1, y = 2
(x, y) = swap(x, y);
println!("x = {}, y = {}", x, y); // x = 2, y = 1
}
앞서 함수의 반환값도 타입 표기를 해야 한다고 이야기했는데, 그럼 함수가 아무것도 반환하지 않을 때는 어떻게 해야할까요?
아래 greeting 함수는 별다른 값을 반환하지 않아요. 이 경우, 반환값의 타입 표기 자체를 생략할 수 있어요.
fn greeting() {
println!("Hello World!");
}
또는, 반환값의 타입을 ()
로 표기할 수 있어요.
fn farewell() -> () {
println!("Good bye!");
}
이 때, 반환값이 없는 함수의 반환값을 println!
등으로 출력하려면 어떻게 해야 할까요? 말이 좀 이상하지만, 이렇게 반환값이 없는 함수의 반환값을 출력하려고 하면 오류가 발생해요.
println!("{}", farewell()); // error[E0277]: `()` doesn't implement `std::fmt::Display`
이럴 때는, 포맷 문자열을 아래처럼 사용해주면 돼요.
println!("{:?}", farewell());