After reading Rust book chapter 19

rust

19.2 Advanced Traits

19.2.1 연관 타입으로 트레이트 정의에 자리지정자 타입 선언

pub trait Iterator {
    type Item;

    fn next(&mut self) -> Option<Self::Item>;
}


// (1)
// Item 타입을 u32 타입으로 대체
impl Iterator for Counter {
    type Item = u32;

    fn next(&mut self) -> Option<Self::Item> {
        // --snip--

// (2)
// 제네릭으로 선언한 가상의 Iterator
pub trait Iterator<T> {
    fn next(&mut self) -> Option<T>;
}


19.2.2 기본 제네릭 타입 매개변수와 연산자 오버로딩


// Add 트레이트를 구현하여
// Point 인스턴스에 대한 + 연산자 오버로딩
use std::ops::Add;

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

impl Add for Point {
    type Output = Point;

    fn add(self, other: Point) -> Point {
        Point {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

fn main() {
    assert_eq!(
        Point { x: 1, y: 0 } + Point { x: 2, y: 3 },
        Point { x: 3, y: 3 }
    );
}
trait Add<Rhs=Self> {
    type Output;

    fn add(self, rhs: Rhs) -> Self::Output;
}


// Millimeters + Meters 연산을 수행하는
// Add 트레이트를 Millimeters 구조체에 정의
use std::ops::Add;

struct Millimeters(u32);
struct Meters(u32);

impl Add<Meters> for Millimeters {
    type Output = Millimeters;

    fn add(self, other: Meters) -> Millimeters {
        Millimeters(self.0 + (other.0 * 1000))
    }
}


19.2.3 불명확성 제거를 위한 완전 식별자 문법: 같은 이름 메서드 호출

trait Pilot {
    fn fly(&self);
}

trait Wizard {
    fn fly(&self);
}

struct Human;

impl Pilot for Human {
    fn fly(&self) {
        println!("This is your captain speaking.");
    }
}

impl Wizard for Human {
    fn fly(&self) {
        println!("Up!");
    }
}

impl Human {
    fn fly(&self) {
        println!("*waving arms furiously*");
    }
}
// (1)
// *waving arms furiously*
fn main() {
  let person = Human;

    person.fly();
}

// (2)
fn main() {
    let person = Human;
    Pilot::fly(&person);
    Wizard::fly(&person);
    person.fly();
}


trait Animal {
    fn baby_name() -> String;
}

struct Dog;

impl Dog {
    fn baby_name() -> String {
        String::from("Spot")
    }
}

impl Animal for Dog {
    fn baby_name() -> String {
        String::from("puppy")
    }
}

// (1)
// Spot 출력
fn main() {
    println!("A baby dog is called a {}", Dog::baby_name());
}

// (2)
// Error!
fn main() {
    println!("A baby dog is called a {}", Animal::baby_name());
}

// (3)
// puppy 출력
fn main() {
    println!("A baby dog is called a {}", <Dog as Animal>::baby_name());
}


19.2.4 Supertraits: 한 트레이트에서 다른 트레이트 기능을 요청

**********
*        *
* (1, 3) *
*        *
**********
use std::fmt;

// 이 트레이트는 Display 트레이트의 기능을 요구함을 명시
trait OutlinePrint: fmt::Display {
    fn outline_print(&self) {
        // 따라서 Display를 구현하는 타입에 자동으로 구현되는
        // to_string 함수를 사용할 수 있다.
        let output = self.to_string();
        let len = output.len();
        println!("{}", "*".repeat(len + 4));
        println!("*{}*", " ".repeat(len + 2));
        println!("* {} *", output);
        println!("*{}*", " ".repeat(len + 2));
        println!("{}", "*".repeat(len + 4));
    }
}


struct Point {
    x: i32,
    y: i32,
}

// (1)
impl OutlinePrint for Point {}

// (2)
use std::fmt;

impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}


19.2.5 뉴타입 패턴으로 외부 타입에 외부 트레이트 구현


use std::fmt;

struct Wrapper(Vec<String>);

impl fmt::Display for Wrapper {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{}]", self.0.join(", "))
    }
}

fn main() {
    let w = Wrapper(vec![String::from("hello"), String::from("world")]);
    println!("w = {}", w);
    // w = [hello, world] 출력
}



19.3 Advanced Types

19.3.1 뉴타입을 이용한 타입안전성과 추상화

// (1)
struct Millimeters(u32);
struct Meters(u32);

// (2)
struct People(HashMap<i32, String>)


19.3.2 타입 별칭으로 동질의 타입 생성

type Kilometers = i32;


Box<dyn Fn() + Send + 'static>
// AS-IS
fn main() {
    let f: Box<dyn Fn() + Send + 'static> = Box::new(|| println!("hi"));

    fn takes_long_type(f: Box<dyn Fn() + Send + 'static>) {
        // --snip--
    }

    fn returns_long_type() -> Box<dyn Fn() + Send + 'static> {
        // --snip--
        Box::new(|| ())
    }
}

// TO-DO
fn main() {
    type Thunk = Box<dyn Fn() + Send + 'static>;

    let f: Thunk = Box::new(|| println!("hi"));

    fn takes_long_type(f: Thunk) {
        // --snip--
    }

    fn returns_long_type() -> Thunk {
        // --snip--
        Box::new(|| ())
    }
}


// (1)
type Result<T> = std::result::Result<T, std::io::Error>;

// (2)
pub trait Write {
    fn write(&mut self, buf: &[u8]) -> Result<usize>;
    fn flush(&mut self) -> Result<()>;

    fn write_all(&mut self, buf: &[u8]) -> Result<()>;
    fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<()>;
}


19.3.3 절대 반환하지 않는 never 타입

fn bar() -> ! {
    // --snip--
}


(1) continue

// (1) O
let guess: u32 = match guess.trim().parse() {
    Ok(num) => num,
    Err(_) => continue,
};

// (2) X
let guess = match guess.trim().parse() {
        Ok(_) => 5,
        Err(_) => "hello",
    };


(2) panic! 매크로

impl<T> Option<T> {
    pub fn unwrap(self) -> T {
        match self {
            Some(val) => val,
            None => panic!("called `Option::unwrap()` on a `None` value"),
        }
    }
}


(3) loop

print!("forever ");

loop {
    print!("and ever ");
}


19.3.4 동적 크기 타입과 Sized 트레이트

// 컴파일되지 않는다.
let s1: str = "Hello there!";
let s2: str = "How's it going?";


Sized 트레이트

// (1)
fn generic<T>(t: T) {
    // --snip--
}

// (2)
fn generic<T: Sized>(t: T) {
    // --snip--
}

// (3)
fn generic<T: ?Sized>(t: &T) {
    // --snip--
}


19.4 Advanced Functions and Closures

19.4.1 함수 포인터

fn add_one(x: i32) -> i32 {
    x + 1
}

// 매개변수 f는 i32 타입을 받아 i32 타입을 반환하는 함수
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
    f(arg) + f(arg)
}

fn main() {
    let answer = do_twice(add_one, 5);

    println!("The answer is: {}", answer);
}


// 인자로 클로저를 받는 map
let list_of_numbers = vec![1, 2, 3];
let list_of_strings: Vec<String> = list_of_numbers.iter().map(|i| i.to_string()).collect();
// 인자로 함수를 받는 map
// to_string 이름의 함수가 여러 곳에 있으므로 뿌리를 명시
// 여기서는 ToString 트레이트의 메서드를 사용했다.
let list_of_numbers = vec![1, 2, 3];
let list_of_strings: Vec<String> = list_of_numbers.iter().map(ToString::to_string).collect();


19.4.2 클로저 반환하기

fn returns_closure() -> dyn Fn(i32) -> i32 {
    |x| x + 1
}
$ cargo build
   Compiling functions-example v0.1.0 (file:///projects/functions-example)
error[E0746]: return type cannot have an unboxed trait object
 --> src/lib.rs:1:25
  |
1 | fn returns_closure() -> dyn Fn(i32) -> i32 {
  |                         ^^^^^^^^^^^ doesn't have a size known at compile-time
  |
  = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
help: use `impl Fn(i32) -> i32` as the return type, as all return paths are of type `[closure@src/lib.rs:2:5: 2:14]`, which implements `Fn(i32) -> i32`
  |
1 | fn returns_closure() -> impl Fn(i32) -> i32 {
  |                         ~~~~~~~~~~~~~~~~~~~

For more information about this error, try `rustc --explain E0746`.
error: could not compile `functions-example` due to previous error



19.5 Macros


19.5.1 매크로와 함수의 차이점


19.5.2 선언적 매크로(declarative macros)


  // vec! 매크로의 간소화된 코드
  #[macro_export]
  macro_rules! vec {
        // $x:expr는 전달되는 표현식이며
        // $x라는 이름을 부여함
      ($( $x:expr ),*) => {
          {
              let mut temp_vec = Vec::new();
              $(
                    // $x 표현식이 일치할 때마다 생성
                    temp_vec.push($x);
              )*
              temp_vec
          }
      };
  }


19.5.3 절차적 매크로(procedural macros)

use proc_macro;

#[some_attribute]
pub fn some_name(input: TokenStream) -> TokenStream {
}


(1) Custom derive Macro 매크로

use hello_macro::HelloMacro;
use hello_macro_derive::HelloMacro;

#[derive(HelloMacro)]
struct Pancakes;

fn main() {
    Pancakes::hello_macro();
}


// hello_macro/src/lib.rs
pub trait HelloMacro {
    fn hello_macro();
}
// hello_macro/hello_macro_derive/Cargo.toml
[lib]
proc-macro = true

[dependencies]
syn = "0.14.4"
quote = "0.6.3"

// hello_macro/hello_macro_derive/src/lib.rs
use proc_macro::TokenStream;
use quote::quote;
use syn;

#[proc_macro_derive(HelloMacro)]
pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
    // 러스트 코드를 파싱해 트리 구성
    let ast = syn::parse(input).unwrap();

    // 트레이트 구현체 빌드
    impl_hello_macro(&ast)
}

fn impl_hello_macro(ast: &syn::DeriveInput) -> TokenStream {
    let name = &ast.ident;
    let gen = quote! {
        impl HelloMacro for #name {
            fn hello_macro() {
                println!("Hello, Macro! My name is {}!", stringify!(#name));
            }
        }
    };
    gen.into()
}


// pancakes/Cargo.toml
[dependencies]
hello-macro = {path = "../hello-macro"}
hello-macro-derive = {path = "../hello-macro/hello-macro-derive"}

// pancakes/src/main.rs
use hello_macro::HelloMacro;
use hello_macro_derive::HelloMacro;

#[derive(HelloMacro)]
struct Pancakes;

fn main() {
    Pancakes::hello_macro();
}


(2) Attribute-like 매크로

// (1)
#[route(GET, "/")]
fn index() {

// (2)
#[proc_macro_attribute]
pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {


(3) Function-like 매크로

// (1)
let sql = sql!(SELECT * FROM posts WHERE id=1);

// (2)
#[proc_macro]
pub fn sql(input: TokenStream) -> TokenStream {