Archive

    [Rustlings] 19. macro

    rust에서 매크로 기능을 사용하면 복잡한 코드를 간편하게 작성할 수 있다. rust로 프로그램을 작성하면 매크로를 사용하는 모습을 많이 볼 수 있는데 println!이나 vec!가 바로 매크로다. rust의 매크로는 다양한 모습이 있다. #[derive(Debug)] #![allow(dead_code)] println!("hello"); macro_rules! name { () => {}; } 이중에서 macro_rules!을 통해 매크로를 만드는 방법에만 집중한다. 매크로 정의는 rust 코드를 작성하는 방식과 다른 점이 있다. 먼저 매크로 정의는 반드시 매크로 호출보다 먼저 위치해야 한다. 그리고 스코프 밖에서도 해당 매크로를 사용하고 싶다면 #[macro_export]를 붙여줘야 한다. macro..

    [Rustlings] 18. thread

    rust도 병렬 프로그래밍을 지원한다. thread::spawn을 통해 스레드를 생성하고 join함수를 통해 해당 스레드를 실행할 수 있다. let handle = thread::spawn(|| { for i in 0..10 { println!("thread : {}", i); } }); handle.join().unwrap(); thread::spawn에 실행할 코드를 클로저로 전달한다. 만약 해당 클로저가 클로저 밖의 변수를 사용한다면 그 변수의 소유권을 클로저로 넘겨야한다. 해당 클로저 앞에 move를 붙이면 클로저가 사용하는 변수의 소유권을 가져온다. let v = vec![1, 2, 3]; let handle = thread::spawn(move || { for i in v { println!(..

    [Rustlings] 17. Standard Library Types

    Rustlings에서는 standard_library_types에서 Box와 Arc, Iterator를 소개한다. Box는 재귀 구조를 가진 타입을 정의할 때 사용되는 타입이다. Rust는 컴파일 타임에 각 타입이 메모리 공간을 얼마나 필요한지 계산한다. 하지만 재귀 구조를 가진 타입은 사용에 따라 필요한 용량이 달라지기 때문에 문제가 발생한다. 그래서 Box 타입이 해당 타입의 포인터 역할을 함으로서 용량 계산 문제를 해결한다. enum List { Cons(i32, Box), Nil, } Arc는 스레드간의 데이터 공유를 안전하게 도와주는 타입이다. 각 스레드는 Arc의 clone 함수를 통해 같은 데이터에 접근할 수 있고, Arc는 해당 데이터가 몇번 공유되는지 관리한다. let some_data ..

    [Rustlings] 16. Testing

    Rust에서 테스트 코드를 작성하려면 tests 모듈에 테스트 함수를 작성해야한다. #cfg[test] mod tests { #[test] fn test_example() { // test code } } tests 모듈 내 함수가 panic을 발생시키면 그 테스트는 실패로 처리된다. 코드가 원하는 값이 제대로 나오는지 확인하려면 assert!나 assert_eq! 매크로를 사용한다. #[cfg(test)] mod tests { #[test] fn test_assert() { assert!(1 == 1); // Ok assert!(1 == 2); // Fail } #[test] fn test_assert_eq() { assert_eq!(2, 1 + 1); // Ok assert_eq!(3 * 2, -6)..

    [Rustlings] 15. trait

    trait은 여러 method를 묶어둔 집합이다. 같은 trait을 가진 타입은 trait에서 지정한 method를 사용할 수 있다. 또한 trait을 함수 매개변수의 타입으로 사용하면 해당 trait을 가진 타입 모두 들어갈 수 있다. trait AppendBar { fn append_bar(self) -> Self; } impl AppendBar for String { fn append_bar(self) -> Self { let mut newString = String::new(); newString.push_str(self.to_str()); newString.push_str("bar"); newString } } impl AppendBar for Vec { fn append_bar(self) ->..

    [Rustlings] 14. Result

    Result는 Rust에서 제공하는 타입이다. Result에는 특정 타입의 값을 가지는 Ok와 오류를 가지는 Err가 있다. Result 타입은 보통 에러가 발생할 수 있는 처리에 사용된다. struct Result { Ok(T), Err(E), } 에러가 발생할 수 있는 처리를 할 때, 정상적으로 수행됬다면 Ok를 통해 결과를 반환하고 에러가 발생했다면 Err를 통해 어떤 에러가 발생했는지 전달한다. let result_parse = input.parse(); let result = match result_parse { Ok(value) => value, Err(_) => { panic!("Error"); }, }

    [Rustlings] 13. Option

    Option은 Rust의 타입 중 하나로 어떤 값을 가지는 Some과 값을 가지지 않는 None이 있다. Option은 Rust에서 다양하게 사용된다. 보통 값을 가지지 않는 경우도 오류 없이 처리할 수 있도록 만들기 위해 사용한다. struct Option { Some(T), None, } Option 값을 처리할 때는 보통 match을 사용한다. 종종 match를 사용하여 조건문이나 반복문을 돌리는 경우가 많아 Rust에서는 if let과 while let으로 따로 문법을 제공한다. if let Some(word) = optional_input { println!("{}", word); } else { println!("Input a vaild word"); } while let Some(i) = v..

    [Rustlings] 12. Generic

    Rust에서 함수나 구조체, enum에 제너릭 타입을 사용할 수 있다. struct Point { x: T, y: T, } impl Point { fn add(&self, other: Point) -> Point { Point { x: &self.x + other.x, y: &self.y + other.y, } } } fn toVec(x: T) -> Vec { vec![x] } 만약 특정 타입에 대해 다른 정의를 넣고 싶다면 안에 특정 타입을 집어 넣으면 된다. 메소드의 경우에는 impl대신 impl에 넣고 특정 구조체 뒤에 특정 타입을 명시한다. fn max(v: &Vec) -> i32 { let mut res = v[0]; for x in v { if (res < x) { res = x; } } re..