러스트(Rust) 입문을 위한 기초 문법

안녕하세요 오늘은 러스트에 대해서 소개해드리려고 합니다. 쉽게 설명드리자면 러스트(Rust)는 성능, 병렬성, 안전성을 중시하는 프로그래밍 언어입니다. 이번 글에서는 기초 문법을 소개하고 간단한 예제 코드를 통해 같이 알아보겠습니다.

러스트

러스트란?

러스트는 성능 면에서 매우 빠르고 메모리 효율적인 프로그래밍 언어로 알려져 있습니다. 런타임이나 가비지 컬렉터가 없어, 성능이 중요한 서비스를 구동하거나 임베디드 장치에서 실행하고, 다른 언어와 쉽게 통합될 수 있습니다.

특징

  • 제로 오버헤드 추상화(Zero-Cost Abstractions): 고수준 추상화는 추가적인 런타임 오버헤드 없이 낮은 수준의 코드로 컴파일됩니다.
  • 컴파일 시간 최적화(Compile-Time Optimizations): 컴파일러는 코드를 최적화하여 빠른 실행 속도와 적은 메모리 사용을 가능하게 합니다.
  • 메모리 안전성(Memory Safety): 소유권 모델은 메모리 안전성을 보장하며, 이는 성능 저하 없이 안전한 코드를 작성할 수 있게 합니다.

러스트는 시스템 프로그래밍 언어로, C++와 유사한 성능을 제공하면서도 메모리 안전성을 향상시키는 장점을 가지고 있습니다. 따라서 러스트는 성능이 중요한 애플리케이션 개발에 적합한 선택이 될 수 있습니다.

설치

러스트를 사용하기 위해서는 먼저 설치가 필요합니다. 공식 웹사이트에서 설치 지침을 따르거나 리눅스에서는 rustup 스크립트를 사용하여 설치할 수 있습니다.

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Hello world

모든 프로그래밍 언어 학습의 시작으로, Hello world를 출력하는 방법에 대해 알아보겠습니다.

fn main() {
    println!("Hello world!");
}

변수

변수는 기본적으로 불변(immutable)입니다. 값을 변경하려면 mut 키워드를 사용해야 합니다.

let x = 5; // 불변 변수
let mut y = 5; // 가변 변수
y += 1; // y는 6

러스트는 컴파일 시간에 타입을 결정하는 정적 타입 언어입니다. 이는 모든 변수의 타입이 컴파일 시에 명확해야 함을 의미합니다. 러스트는 다양한 데이터 타입을 제공하여, 프로그래머가 정밀하게 데이터를 제어할 수 있도록 합니다.

기본 데이터 타입

  • 정수형(Integer Types): i8, i16, i32, i64, i128, isize (시스템 아키텍처에 따라 크기가 결정되는 정수형), 그리고 이들의 부호 없는 버전인 u8, u16, u32, u64, u128, usize.
  • 부동소수점(Floating-Point Types): f32f64는 IEEE-754 표준을 따릅니다.
  • 불리언(Boolean Type): booltrue 또는 false 값을 가집니다.
  • 문자(Character Type): char는 유니코드 스칼라 값을 나타내며, 작은따옴표(‘)로 묶여 있습니다.

복합 데이터 타입

  • 튜플(Tuple Types): 서로 다른 타입의 몇 개의 값을 하나로 묶을 수 있습니다. 예를 들어, (i32, f64, u8)는 정수, 부동소수점, 그리고 부호 없는 정수를 포함하는 튜플입니다.
  • 배열(Array Types): 모든 요소가 같은 타입인 고정된 길이의 리스트입니다. 예: [i32; 5]i32 타입의 5개 요소를 가진 배열입니다.

소유권

소유권 시스템은 메모리 안전성을 보장하고, 데이터 손실을 방지합니다. 소유권 규칙은 다음과 같습니다:

  1. 각각의 값은 해당 값을 소유하는 변수(owner)를 갖습니다.
  2. 한 번에 하나의 소유자만이 존재할 수 있습니다.
  3. 소유자가 스코프(scope)를 벗어나면, 값은 버려집니다(dropped).
let s1 = String::from("hello");
let s2 = s1; // s1의 소유권이 s2로 이동
// 이 시점에서 s1은 더 이상 유효하지 않음
println!("{}, world!", s1); // 에러

함수

러스트에서 함수는 fn 키워드로 정의됩니다. 매개변수와 반환 타입을 명시할 수 있습니다.

fn add_two(x: i32) -> i32 {
    x + 2
}

소유권

함수에 값을 전달할 때도 소유권이 이동하거나, 값이 복사됩니다.

fn take_ownership(some_string: String) {
    println!("{}", some_string);
}

let s = String::from("hello");
take_ownership(s);
// s는 더 이상 유효하지 않음

데이터 타입과 소유권 시스템은 프로그램의 안전성과 효율성을 크게 향상시킵니다. 이러한 시스템을 통해 메모리 오류와 병렬 처리 문제를 줄일 수 있으며, 더욱 견고한 프로그램을 개발할 수 있습니다.

제어 흐름

if 문과 loop, while, for 반복문을 사용하여 프로그램의 제어 흐름을 관리할 수 있습니다.

let number = 6;

if number % 2 == 0 {
    println!("{} is even", number);
} else {
    println!("{} is odd", number);
}

for i in 0..5 {
    println!("{}", i); // 0부터 4까지 출력
}

지금까지 러스트의 기초 문법과 개념을 소개하는 데에 초점을 맞추었습니다. 러스트는 C++과 비교할 때 유사한 성능을 제공하면서도 메모리 안전성을 향상시키는 장점을 가지고 있으니 성능이 중요한 프로그램 개발에 적합한 선택이 될 수 있습니다. 이 글이 도움이 되길 바랍니다. 감사합니다.