변수 선언하고 값 출력하기
파이썬에서는 모든 객체를 print 함수로 출력할 수 있습니다. 문자열 "Hello, world!" 를 출력하는 예제는 다음과 같습니다.
print("Hello, world!")
러스트에서는 매크로(macro)를 사용해 값을 출력합니다. 매크로란 사전 정의된 편리한 기능을 의미하고, 항상 이름 뒤에 !가 붙습니다. 러스트 코드는 매 줄의 마지막에 세미콜론(;) 이 붙습니다. 위의 파이썬 예제와 동일하게 문자열 "Hello, world!" 를 출력하는 코드는 다음과 같습니다.
fn main() {
println!("Hello, world!");
}
변수 선언
파이썬은 변수 선언 시 타입을 명시하지 않아도 되기 때문에 실수값과 정수값 모두 변수에 바로 할당이 가능합니다. 파이썬에서 변수 x 와 y 를 선언하고 실수 1.0과 정수 10을 할당한 다음 두 변수의 값을 출력합니다.
x = 1.0
y = 10
print(f"x = {x}, y = {y}")
파이썬 코드 실행 결과는 다음과 같습니다.
x = 1.0, y = 10
러스트에서는 let 키워드를 사용해 변수를 선언합니다. 그리고 타입을 : 뒤에 명시합니다.
변수명 타입 값
let x: i32 = 10;
대부분의 경우에서는 컴파일러가 타입을 추측해주지만, 몇몇 경우에는 직접 타입을 명시해줘야 하기도 합니다. 아래 예제에서는 실수 1.0을 f64 타입으로 선언했지만, 실제로는 변수 y와 같이 명시적으로 타입을 적어주지 않아도 컴파일이 됩니다. 다음으로 prinln! 매크로에서는 문자열의 {} 자리에 변수가 순서대로 들어가 전체 문자열이 완성됩니다.
fn main() {
let x: f64 = 1.0;
let y = 10;
println!("x = {}, y = {}", x, y);
}
결과를 확인해보겠습니다.
x = 1, y = 10
작명 규칙
파이썬과 러스트의 작명 규칙은 정말 비슷합니다. 대표적인 몇 가지 경우를 살펴보면 다음과 같습니다.
파이썬 | 러스트 | |
변수 | snake_case = 3 | let snake_case = 3; |
함수 | def my_function | fn my_function |
클래스/구조체 | class MyClass | struct MyStruct |
상수 | SCREAMING_SNAKE_CASE = 1 | const SCREAMING_SNAKE_CASE: i32 = 1; |
- 변수와 함수의 경우, 둘 다 스네이크 케이스(Snake case)를 사용합니다. 스네이크 케이스란, 모든 단어를 숫자 또는 알파벳 소문자로 작성하고, 단어 구분은 언더바(_)로 합니다. 단 변수명은 반드시 알파벳 소문자로만 시작해야 합니다.
- 파이썬의 클래스와 러스트 구조체는 파스칼 케이스(Pascal case)를 사용합니다. 파스칼 케이스는 대문자로 단어를 시작하고, 단어 구분을 대문자로 하는 작명법입니다.
- 상수의 경우는 둘 다 스크리밍 스네이크 케이스(Screaming snake case)를 사용합니다. 모든 알파벳이 대문자이고, 단어 구분을 언더바로 합니다. 단, 러스트의 상수는 반드시 타입을 명시해야 합니다.
변수의 불변성
불변성
파이썬에서는 변수를 선언한 다음 다른 값을 넣는 것이 매우 자유롭습니다. 변수의 타입도 상관 없이 새로운 값을 마음대로 넣을 수 있습니다.
x = 1
x = "2"
x = 3.141592
러스트의 모든 변수는 기본적으로 불변(immutable)입니다. 예를 들어, 아래 코드와 같이 let 키워드로 변수를 선언하고, 해당 변수의 값을 바꾸려고 한다면 컴파일이 되지 않습니다.
fn main() {
let x = 1;
x = 2; // won't compile!
println!("{}", x);
}
위 코드를 실행해보면 다음과 같은 에러가 발생합니다.
error[E0384]: cannot assign twice to immutable variable `x`
--> src/main.rs:3:5
|
2 | let x = 1;
| -
| |
| first assignment to `x`
| help: consider making this binding mutable: `mut x`
3 | x = 2; // won't compile!
| ^^^^^ cannot assign twice to immutable variable
처음 let x=1 로 선언된 변수가 불변(immutable)이기 때문에 값을 두 번 할당할 수 없다고 합니다. help에서 변수 x 를 가변 변수(mutable)로 다음과 같이 선언하라고 합니다.
let mut x = 1;
수정된 코드를 아래와 같이 작성하고 실행해봅니다.
fn main() {
let mut x = 1;
x = 2;
println!("{}", x);
}
값 2가 잘 출력되는 것을 알 수 있습니다. 이처럼, 러스트에서는 모든 변수의 값이 불변으로 선언이 됩니다. 따라서 값을 바꾸고자 하는 변수에는 mut 키워드로 가변성을 부여해야 합니다.
섀도잉
한번 선언한 불변 변수의 값을 변경하는 것은 불가능하지만, 변수 자체를 새로 선언하는 것은 가능합니다. 이렇게 변수 이름을 재사용해서 새로운 변수를 다시 선언하는 것을 섀도잉(shadowing)이라고 합니다.
섀도잉을 사용할 경우, mut 키워드 없이도 새로운 값을 변수에 할당할 수 있고, 새로운 변수이기 때문에 타입도 변경할 수 있습니다. 아래 예제에서는 변수 x 에 처음에는 "5" 라는 문자열을 할당했지만, 그 다음에는 섀도잉을 사용해 x에 정수 6을 할당했습니다. 코드를 실행해보면 정상적으로 컴파일됩니다.
fn main() {
let x = "5";
let x = 6; // x is redeclared as 6
println!("The value of x is: {}", x); // 6
}
타입
C언어 계열과 마찬가지로, Rust는 타입이 존재합니다. 러스트의 원시 타입(primitive type) 목록은 다음과 같습니다.
이름타입
이름 | 타입 |
8비트 정수 | i8 |
16비트 정수 | i16 |
32비트 정수 | i32 |
64비트 정수 | i64 |
128비트 정수 | i128 |
아키텍처 | isize |
부호 없는 8비트 정수 | u8 |
부호 없는 16비트 정수 | u16 |
부호 없는 32비트 정수 | u32 |
부호 없는 64비트 정수 | u64 |
부호 없는 128비트 정수 | u128 |
부호 없는 아키텍처 | usize |
불리언 | bool |
문자열 | String |
문자열 슬라이스 | str |
32비트 부동소수점 실수 | f32 |
64비트 부동소수점 실수 | f64 |
타입 추론
개발자가 변수에 타입을 지정하지 않아도 앞에서 설치한 rust-analyzer가 알아서 타입을 추론(inference)해서 화면에 보여줍니다. 비슷한 원리로 코드가 컴파일될 때에는 컴파일러가 타입을 추론해서 변수를 선언하게 됩니다. 이때, 추측되는 타입의 기본값은 정수형은 i32 , 실수형은 f64 입니다.
다음 코드를 VSCode에 붙여넣으면 아래 그림과 같이 타입이 추론되는 것을 볼 수 있습니다.
fn main(){
let x = 1;
let y = 1.0;
println!("{} {}", x, y);
}
마찬가지로 이 상태로도 컴파일이 잘 실행되고, 컴파일러가 각 변수를 i32 와 f64 로 추측해서 컴파일합니다.
실행결과
1 1
타입 캐스팅
파이썬에서는 타입 이름을 바로 사용해 타입 변환을 수행합니다.
x = 1.2
y = int(x)
print(f"{x} -> {y}");
실행결과
1.2 -> 1
러스트에서는 아래와 같이 as 키워드를 사용하면 됩니다. 예제에서는 64비트 실수 f64 로 선언된 변수 x 의 값을 32비트 정수 i32 로 변환해 y 변수에 할당하고 있습니다. 실수에서 정수로 변환했기 때문에 값이 1.2에서 1로 변경됩니다.
fn main() {
let x: f64 = 1.2;
let y = x as i32;
println!("{} -> {}", x, y);
}
실행결과
1.2 -> 1
상수
상수(constant)란, 한 번 선언되면 값이 바뀌지 않는 변수를 의미합니다.
파이썬에서 상수를 다음과 같이 선언해 보겠습니다.
THRESHOLD = 10
def is_big(n: int) -> bool:
return n > THRESHOLD
if __name__ == '__main__':
print(THRESHOLD)
print(is_big(THRESHOLD))
THRESHOLD = 5
실행 결과
10
False
일반적으로 상수는 모듈의 가장 위에 선언합니다. 이렇게 선언하게 되면, 모듈의 모든 범위에서 상수에 접근하는 것이 가능합니다. is_big 이라는 함수 안에서도 상수 THRESHOLD 를 사용할 수 있고, 함수를 실행하는 if 문 안에서도 THRESHOLD 를 사용합니다. 하지만 파이썬의 모든 변수는 기본적으로 가변이기 때문에 위에서 선언한 상수를 변경할 수 있다는 문제가 있습니다.
러스트에서 동일한 내용을 구현해 보겠습니다.
const THRESHOLD: i32 = 10;
fn is_big(n: i32) -> bool {
n > THRESHOLD
}
fn main() {
println!("{}", THRESHOLD);
println!("{}", is_big(5));
}
실행결과
10
false
러스트에서는 상수를 const 키워드로 선언하게 됩니다. 이렇게 선언된 상수는 불변이기 때문에 값을 변경할 수 없습니다. 파이썬에서 상수를 모듈 전체에서 접근할 수 있었던 것처럼, 마찬가지로 러스트에서도 선언된 상수 THRESHOLD 를 함수 is_big 과 main 내부에서 참조하는 것이 가능합니다. 하지만 값이 불변이기 때문에 THRESHOLD = 5;와 같이 새로운 값을 할당하게 되면 오류가 발생합니다.
const THRESHOLD: i32 = 10;
fn is_big(n: i32) -> bool {
n > THRESHOLD
}
fn main() {
println!("{}", THRESHOLD);
println!("{}", is_big(5));
THRESHOLD = 5;
}
실행결과
--> src/main.rs:11:15
|
11 | THRESHOLD = 5;
| --------- ^
| |
| cannot assign to this expression
컴파일러가 친절하게 상수 THRESHOLD 에는 새로운 값을 할당할 수 없다고 알려주게 됩니다. 실행하기 전 편집기 안에서도 빨간 줄로 해당 코드에 문제가 있음을 알려주기 때문에 문제를 빠르게 찾고 해결할 수 있습니다.
'Rust' 카테고리의 다른 글
Rust 반복문 (83) | 2023.04.20 |
---|---|
Rust 함수 (90) | 2023.04.19 |
개발자들이 가장 사랑하는 언어 Rust 소개 (158) | 2023.04.17 |
Tauri 설치부터 배포까지 (리눅스 빌드) (96) | 2023.04.16 |
Tauri 배포 (53) | 2023.04.15 |