cargo new --lib adder
sijin@Sijin:~/rust/adder$ tree
.
├── Cargo.toml
└── src
└── lib.rs
2 directories, 2 files
cargo new --lib [name] 명령어로 만들 수 있다pub fn add(left: u64, right: u64) -> u64 {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
cfg(test)는 코드가 test 환경에서만 컴파일되도록 한다cargo new calc
# calc 패키지의 Cargo.toml
[package]
name = "calc"
version = "0.1.0"
edition = "2024"
[dependencies]
adder = {path = "../adder"}
fn main() {
let ret = adder::add(1, 2);
println!("{}", ret);
}
adder/
├── Cargo.lock
├── Cargo.toml
├── src
│ ├── business
│ │ ├── mod.rs
│ │ └── user.rs
│ ├── database
│ │ ├── mod.rs
│ │ └── user_dao.rs
│ └── lib.rs
# database/user_dao.rs
pub fn create() {
println!("database::user_dao::create");
}
# database/mod.rs
pub mod user_dao;
# business/user.rs
pub fn create() {
println!("database::user::create");
}
# business/mod.rs
pub mod user;
pub mod business;
pub mod database;
#[test]
fn it_works() {
business::user::create();
database::user_dao::create();
}
pub fn create() {
println!("database::user::create");
super::super::database::user_dao::create();
}
super를 통해 상위폴더의 모듈에 접근할 수 있다pub fn create() {
println!("database::user::create");
crate::database::user_dao::create();
}
crate를 통해 크레이트를 기준으로 모듈을 찾을 수 있다public private같은 가시성 제어는 pub 키워드를 사용해 적용할 수 있다| 제한자 | 내용 |
|---|---|
| pub | 정보를 모두 노출 |
| pub(in 대상 모듈) | 제한된 경로에 한정해서 정보를 노출 |
| pub(crate) | 현재 crate에 한정하여 정보를 노출 |
| pub(super) | 상위 모듈에 한정해서 정보를 노출 |
| 생략 or pub(self) | 정보를 외부에 노출하지 않음 |
mod my_module {
pub fn public_fn() { ... };
fn public_fn() { ... };
pub(crate) public_fn {};
pub(super) public_fn {};
}
enum Result<T, E> {
Ok(T),
Err(E),
}
use core::panic;
use std::fs::File;
fn main() {
let res = File::open("test.txt");
let _f = match res {
Ok(f) => f,
Err(err) =>{
panic!("file open fail: {:?}", err);
}
};
println!("file open success");
}
Result<std::fs::File, std::io::Error>이다unwrap, expect, ?를 사용해 쉽게 오류를 대응할 수 있다use std::fs::File;
fn main() {
let res = File::open("test.txt").unwrap();
println!("file open success");
}
use std::fs::File;
fn main() {
let res = File::open("test.txt").expect("!!my custom error message!!");
println!("file open success");
}
=> 오류 발생 시 아래처럼 출력됨
thread 'main' panicked at src/main.rs:4:38:
!!my custom error message!!: Os { code: 2, kind: NotFound, message: "No such file or directory" }
fn read_file() -> Result<String, io::Error> {
let mut str = String::new();
let mut file = File::open("test.txt")?;
file.read_to_string(&mut str)?;
return Ok(str);
}
? 키워드는 Result 타입의 값이 Ok면 그 값을 반환하고, Err이면 그 즉시 함수에서 Err를 반환한다File::open, file.read_to_string 각각 함수에서 실패 시 즉시 read_file 함수에서 Err를 리턴한다복구 불가능한 오류는 아래와 같은 예시가 있다
fn div(a: i32, b: i32) -> i32 {
a / b
}
fn main() {
div(1, 0);
}
RUST_BACKTRACE=1 cargo run
fn div(a: i32, b: i32) -> i32 {
if(b == 0) {
panic!("devide with 0")
}
a / b
}
panic!으로 복구 불가능한 오류를 발생시킬 수 있다panic!이 발생할 수 있다고 명시하는 것이 좋다panic!을 마주할 수 있다fn main() {
let mut v: Vec<i32> = Vec::new();
for i in 1..10 {
v.push(i);
}
for d in &v {
print!("{}", d);
}
}
fn main() {
let v: Vec<i32> = vec![0, 1, 2, 3, 4];
for d in &v {
print!("{}", d);
}
}
Vec::new는 vec![] 매크로로 대체할 수 있다fn main() {
let v: Vec<i32> = vec![0, 1, 2, 3, 4];
let one = v[0];
let two = v.get(1);
let nine = v.get(9);
println!("{} {:?} {:?}", one, two, nine); // => 0 Some(1) None
}
fn main() {
let mut v: Vec<i32> = vec![0, 1, 2, 3, 4];
v[1] = 100;
for i in &mut v {
*i = *i * 100;
}
for d in &v {
print!("{} ", d);
}
}
use std::collections::LinkedList;
fn main() {
let mut linkedlist: LinkedList<i32> = LinkedList::new();
for i in 1..10 {
linkedlist.push_back(i);
}
println!("{:?}", linkedlist.iter().nth(7));
}
use std::collections::LinkedList;
fn main() {
let mut linkedlist: LinkedList<i32> = LinkedList::new();
for i in 1..10 {
linkedlist.push_back(i);
}
for d in linkedlist.iter_mut() {
*d = *d * 10;
}
for d in linkedlist.iter() {
print!("{} ", d);
}
}
use std::collections::HashMap;
fn main() {
let mut hashmap: HashMap<i32, String> = HashMap::new();
hashmap.insert(10, String::from("aaa"));
hashmap.insert(20, String::from("bbb"));
let aaa = hashmap.get(&10); // key는 빌림 형식
for (key, value) in &hashmap {
println!("{} {}", key, value);
}
}
use std::collections::{HashSet};
fn main() {
let mut hashset: HashSet<String> = HashSet::new();
hashset.insert(String::from("aaa"));
hashset.insert(String::from("bbb"));
hashset.insert(String::from("aaa"));
for data in &hashset {
println!("{}", data);
}
if hashset.contains("aaa") == false {
println!("aaa가 없음");
}
}
use std::collections::{BinaryHeap};
fn main() {
let mut heap: BinaryHeap<i32> = BinaryHeap::new();
heap.push(1);
heap.push(3);
heap.push(2);
while heap.is_empty() == false {
println!("{:?}", heap.pop());
}
}
use std::fmt::format;
fn main() {
let mut str1 = String::new();
str1.push_str("hello");
let str1 = format!("{} {}", str1, String::from("world"));
println!("{}", str1);
for c in str1.chars() {
print!("{} ", c);
}
}
&str을 가지고 있다&str은 문자들을 배열로 관리해서 크기를 늘리거나 줄이는 것이 불가능하다&str과 같이 빌림 형식을 취하는 것이 일반적이다fn main() {
let vec = vec![1, 2, 3];
for item in vec.iter() {
println!("{}", item);
}
println!("{:?}", vec); // [1, 2, 3] 출력
}
fn main() {
let vec = vec![1, 2, 3];
for item in vec.into_iter() {
println!("{}", item);
}
println!("{:?}", vec); // 컴파일 오류
}