러스트 표준 트레잇
#[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를 사용하면 다양한 포맷팅, 파싱, 고급 기능들을 사용할 수 있다