러스트 표준 트레잇

  • #[derive(TraitName)]을 붙이면, 러스트 컴파일러는 해당 타입에 대해 선택한 트레잇의 구현 코드를 자동으로 생성한다

copy

#[derive(Debug, Clone, Copy)]
struct Point {
    x: i32,
    y: i32,
}

fn add_points(p1: Point, p2: Point) -> Point {
    Point {
        x: p1.x + p2.x,
        y: p1.y + p2.y
    }
}

fn main() {
    let a = Point {x: 1, y: 2};
    let b = Point {x: 2, y: 3};

    let res = add_points(a, b); // add_point에 a, b로 인자로 들어갔지만

    println!("{:?}", a); // 소유권을
    println!("{:?}", b); // 잃지 않았다
    println!("{:?}", res);
}
  • 러스트의 소유권 시스템은 메모리 안전성을 보장하기 위한 핵심 매커니즘이다
  • Copy는 기본적인 데이터 타입에 대해 별도 소유권 전달 없이도 값을 복사할 수 있게 해준다
  • Copy 트레잇은 바이트 단위의 깊은 복사를 수행한다
  • Copy 트레잇이 적용된 구조체는 =으로 묵시적 복사가 이루어진다
  • 위 예제에서는 add_points 함수로 a, b가 들어갔지만 소유권이 전달된게 아니라 값이 복제되어 전달된 형태라서, main 함수가 소유권을 그대로 갖는다

Clone

#[derive(Debug)]
struct Person {
    name: String,
    age: i32,
}

impl Clone for Person {
    fn clone(&self) -> Self {
        Person {
            name: self.name.clone(),
            age: self.age
        }
    }  
}

fn main() {
    let person1 = Person {name: String::from("name"), age: 12};
    let person2 = person1.clone();

    println!("{:?}", person1); // person1 소유권 잃지 않음
    println!("{:?}", person2);
}
  • clone은 copy와 비슷하게 객체를 복사한다
  • 다른점은, clone은 명시적으로 clone() 함수를 호출해야 하는 명시적 복사이다
  • clone은 위 예시처럼 clone() 함수를 직접 정의해서 복사 방식을 custom 할 수 있다

Drop

struct Person {
    name: String,
    age: i32,
}

impl Drop for Person {
    fn drop(&mut self) {
        println!("{} is dropped", self.name);
    }
}


fn main() {
    {
        let person1 = Person {name: String::from("name"), age: 12};
    } // name is dropped 로그가 먼저 나오고
    println!("out of scope"); // out of scope 로그가 나옴
}
  • 러스트는 소유권 시스템을 통해 메모리를 관리한다
  • 그러나 파일, 소켓, 비트맵 등 특정 자원은 소유권과 라이프사이클이 다르다
  • 리소스나 객체가 메모리에서 해제될 때 특정 작동을 실행하기 위해 Drop 트레잇이 사용된다

From & Into

#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

impl From<(i32, i32)> for Point {
    fn from(value: (i32, i32)) -> Self {
        Point {x: value.0, y: value.1}
    }
}

fn main() {
    let point1 = Point::from((1, 2));
    let point2: Point = (2, 3).into();

    println!("{:?}", point1);
    println!("{:?}", point2);
}
  • 타입 간 변환을 위해 From과 Into를 사용할 수 있다
  • 위 예제에서는 from을 통해 받은 tuple (1, 2)를 impl에 선언된대로 Point로 변환하였고
  • into를 호출하여 Point::from에서 선언된대로 tuple (2, 3)을 Point로 변환했다

AsRef

#[derive(Debug)]
struct Person {
    name: String,
    age: i32,
}

impl AsRef<str> for Person {
    fn as_ref(&self) -> &str {
        &self.name
    }
}

fn print_name<P: AsRef<str>>(person: P) {
    println!("{}", person.as_ref());
}

fn main() {
    let person = Person {name: String::from("Alice"), age: 23};

    print_name(person);
    print_name(String::from("Bob"));
    print_name("Dart");
}
  • AsRef는 객체를 참조값으로 변환하는 용도로 사용된다
  • 함수가 다양한 자료형의 참조를 받아들일 수 있도록 한다
  • 제네릭 함수나 다양한 타입을 처리하는 함수에서 입력 타입의 다양성을 확장시킬 수 있다

AsMut

#[derive(Debug)]
struct Person {
    name: String,
    age: i32,
}

impl AsMut<String> for Person {
    fn as_mut(&mut self) -> &mut String {
        &mut self.name
    }
}

fn change_name<P: AsMut<String>, S: AsRef<str>>(person: &mut P, new_name: S) {
    let name = person.as_mut();
    name.clear();
    name.push_str(new_name.as_ref());
}

fn main() {
    let mut person = Person {name: String::from("Alice"), age: 23};

    change_name(&mut person, "Bob");
    println!("{:?}", person);

    change_name(&mut person, String::from("Dart"));
    println!("{:?}", person);
}
  • AsMut은 수정 가능한 참조로 변경하는 트레잇이다
  • AsMut 트레잇을 활용하여 change_name 함수에서 name을 수정 가능한 &mut String 형태로 변환하였다

시스템콜

std::os

  • std::os 안에는 std::os::windows, std::os::linux 같은 서브 모듈들이 존재해서, 각 운영체제별로 특화된 기능, 인터페이스를 제공한다
use std::{os::unix::fs::PermissionsExt, path::Path};

fn main() {
    let path = Path::new("test.txt");
    let metadata = path.metadata().unwrap();

    let permissions = metadata.permissions();
    let mode = permissions.mode();

    println!("{:o}", mode)
}

# 파일
sijin@Sijin:~/rust/calc$ ls -al test.txt 
-rw-r--r-- 1 sijin sijin 0 Sep 28 17:07 test.txt

std::env

  • 현재 실행중인 프로세스에 전달된 arguments나
  • 환경변수를 조회할 수 있다

std::process

  • 프로세스의 생성, 관리, 종료 등 기능을 제공

시간, 날짜 관련

SystemTime

use std::{thread::sleep, time::{Duration, SystemTime}};

fn main() {
    let time = SystemTime::now();

    sleep(Duration::from_millis(1234));

    let elapsed = time.elapsed().unwrap();

    println!("{}.{} sec", elapsed.as_secs(), elapsed.subsec_millis()); // 1.234 sec
}
  • 현재 시스템 시간을 활용할 수 있다
  • 구간 시간 측정 등 활용할 수 있다

chrono

# Cargo.toml 파일
[dependencies]
chrono = "*"
use chrono::Local;

fn main() {
    let now = Local::now();

    println!("{}", now.format("%Y-%m-%d")); // 2025-09-28
}
  • chrono crate를 사용하면 다양한 포맷팅, 파싱, 고급 기능들을 사용할 수 있다

0개의 댓글