After reading Rust book chapter 10

rust

Removing Duplication by Extracting a Function

// (1)
fn main() {
    let number_list = vec![34, 50, 25, 100, 65];

    let mut largest = number_list[0];

    for number in number_list {
        if number > largest {
            largest = number;
        }
    }

    println!("The largest number is {}", largest);
}
// (2)
fn largest(list: &[i32]) -> i32 {
  let mut largest = list[0];

  for &item in list {
      if item > largest {
          largest = item;
      }
  }

  largest
}

fn main() {
    let number_list = vec![34, 50, 25, 100, 65];

    let result = largest(&number_list);
    println!("The largest number is {}", result);

    let number_list = vec![102, 34, 6000, 89, 54, 2, 43, 8];

    let result = largest(&number_list);
    println!("The largest number is {}", result);
}



제네릭 데이터 타입

함수에서의 사용

// (1)
fn largest_i32(list: &[i32]) -> i32 {...}
fn largest_char(list: &[char]) -> char {...}

// (2)
fn largest<T>(list: &[T]) -> T {...}


구조체에서의 사용

// (1) 타입 T를 일반화한 구조체
struct Point<T> {
    x: T,
    y: T,
}

fn main() {
    let integer = Point { x: 5, y: 10 };
    let float = Point { x: 1.0, y: 4.0 };
}
// (2) 다중 제네릭 타입 구조체
struct Point<T, U> {
    x: T,
    y: U,
}

fn main() {
    let both_integer = Point { x: 5, y: 10 };
    let both_float = Point { x: 1.0, y: 4.0 };
    let integer_and_float = Point { x: 5, y: 4.0 };
}


열거자에서의 사용

// (1)
enum Option<T> {
    Some(T),
    None,
}

// (2)
enum Result<T, E> {
    Ok(T),
    Err(E),
}


메서드에서의 사용

// (1)
struct Point<T> {
    x: T,
    y: T,
}

impl<T> Point<T> {
    fn x(&self) -> &T {
        &self.x
    }
}

fn main() {
    let p = Point { x: 5, y: 10 };

    println!("p.x = {}", p.x());
}
// (2)
impl Point<f32> {
    fn distance_from_origin(&self) -> f32 {
        (self.x.powi(2) + self.y.powi(2)).sqrt()
    }
}
struct Point<X1, Y1> {
    x: X1,
    y: Y1,
}

impl<X1, Y1> Point<X1, Y1> {
    fn mixup<X2, Y2>(self, other: Point<X2, Y2>) -> Point<X1, Y2> {
        Point {
            x: self.x,
            y: other.y,
        }
    }
}

fn main() {
    let p1 = Point { x: 5, y: 10.4 };
    let p2 = Point { x: "Hello", y: 'c' };

    let p3 = p1.mixup(p2);

    println!("p3.x = {}, p3.y = {}", p3.x, p3.y);
}


제네릭의 성능

// (1)
let integer = Some(5);
let float = Some(5.0);

// (2)
num Option_i32 {
    Some(i32),
    None,
}

enum Option_f64 {
    Some(f64),
    None,
}

fn main() {
    let integer = Option_i32::Some(5);
    let float = Option_f64::Some(5.0);
}



트레이트(trait): Defining Shared Behavior


트레이트 선언하기

pub trait Summary {
    fn summarize(&self) -> String;
}


타입에 트레이트 구현하기

// (1)
pub struct NewsArticle {
    pub headline: String,
    pub location: String,
    pub author: String,
    pub content: String,
}

impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("{}, by {} ({})", self.headline, self.author, self.location)
    }
}

pub struct Tweet {
    pub username: String,
    pub content: String,
    pub reply: bool,
    pub retweet: bool,
}

impl Summary for Tweet {
    fn summarize(&self) -> String {
        format!("{}: {}", self.username, self.content)
    }
}
// (2)
use aggregator::{Summary, Tweet};

fn main() {
    let tweet = Tweet {
        username: String::from("horse_ebooks"),
        content: String::from(
            "of course, as you probably already know, people",
        ),
        reply: false,
        retweet: false,
    };

    println!("1 new tweet: {}", tweet.summarize());
}


트레이트 기본 구현 (Default Implementations)

// (1)
pub trait Summary {
    fn summarize_author(&self) -> String;

    fn summarize(&self) -> String {
        format!("(Read more from {}...)", self.summarize_author())
    }
}
// (2)
impl Summary for Tweet {
    fn summarize_author(&self) -> String {
        format!("@{}", self.username)
    }
}
// (3)
let tweet = Tweet {
    username: String::from("horse_ebooks"),
    content: String::from(
        "of course, as you probably already know, people",
    ),
    reply: false,
    retweet: false,
};

println!("1 new tweet: {}", tweet.summarize());


트레이트 매개변수 (Traits as Parameters)

pub fn notify(item: &impl Summary) {
    println!("Breaking news! {}", item.summarize());
}


(1) Trait Bound Syntax

// (1)
pub fn notify<T: Summary>(item: &T) {
    println!("Breaking news! {}", item.summarize());
}

// (2)
pub fn notify<T: Summary>(item1: &T, item2: &T) {...}


(2) + 문법으로 여러 트레이트 경계 정의하기

// (1)
pub fn notify(item: &(impl Summary + Display)) {...}

// (2)
pub fn notify<T: Summary + Display>(item: &T) {...}


(3) where 이용해 트레이트 경계 정리하기

// (1)
fn some_function<T: Display + Clone, U: Clone + Debug>(t: &T, u: &U) -> i32 {...}

// (2)
fn some_function<T, U>(t: &T, u: &U) -> i32
    where T: Display + Clone,
          U: Clone + Debug
{...}


반환값에 트레이트 구현 값 사용하기

fn returns_summarizable() -> impl Summary {
    Tweet {
        username: String::from("horse_ebooks"),
        content: String::from(
            "of course, as you probably already know, people",
        ),
        reply: false,
        retweet: false,
    }
}


트레이트 경계 예제: largest 함수

// (1)
fn largest<T: PartialOrd>(list: &[T]) -> T {...}

// (2)
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
    let mut largest = list[0];

    for &item in list {
        if item > largest {
            largest = item;
        }
    }

    largest
}

fn main() {
    let number_list = vec![34, 50, 25, 100, 65];

    let result = largest(&number_list);
    println!("The largest number is {}", result);

    let char_list = vec!['y', 'm', 'a', 'q'];

    let result = largest(&char_list);
    println!("The largest char is {}", result);
}
// (3)
fn largest<T: PartialOrd>(list: &[T]) -> &T {
    let mut largest = &list[0];

    for item in list {
        if item > largest {
            largest = &item;
        }
    }

    largest
}

...


덮개 구현 (blanket implementations)

// (1)
impl<T: Display> ToString for T {
    // --snip--
}

// (2)
let s = 3.to_string();



수명(Lifetimes)을 이용힌 참조 유효성 검사


Generic Lifetimes in Functions

fn main() {
    let string1 = String::from("abcd");
    let string2 = "xyz";

    let result = longest(string1.as_str(), string2);
    println!("The longest string is {}", result);
}

fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}


LifeTime Annotation

// 참조
&i32

// 수명을 지정한 참조
&'a i32

// 수명을 지정한 변경가능한 참조
&'a mut i32


Lifetime Annotations in Function Signatures

// (1)
// longest 함수 수정
fn main() {
    let string1 = String::from("abcd");
    let string2 = "xyz";

    let result = longest(string1.as_str(), string2);
    println!("The longest string is {}", result);
}

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}
// (2)
fn main() {
    let string1 = String::from("long string is long");
    let result;
    // ⛔️ borrowed value does not live long enough
    {
        let string2 = String::from("xyz");
        result = longest(string1.as_str(), string2.as_str());
    }
    println!("The longest string is {}", result);
}

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}


Lifetime은 함수에서 언제 사용할까?

// y에는 'a를 사용하지 않음
// x와도, 반환타입과도 관련이 없기 때문
fn longest<'a>(x: &'a str, y: &str) -> &'a str {
    x
}


Lifetime Annotations in Struct Definitions

struct ImportantExcerpt<'a> {
    part: &'a str,
}

fn main() {
    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.').next().expect("Could not find a '.'");
    let i = ImportantExcerpt {
        part: first_sentence,
    };
}

fn main() {
    {
        let novel = String::from("Call me Ishmael. Some years ago...");
    }
    let first_sentence = novel.split('.').next().expect("Could not find a '.'");
    let i = ImportantExcerpt {
        part: first_sentence,
    };

    println!("{}", i.part);
}


Lifetime Elision

fn first_word(s: &str) -> &str {...}

// 1번 규칙 적용
fn first_word<'a>(s: &'a str) -> &str {...}

// 2번 규칙 적용 - 완성!
fn first_word<'a>(s: &'a str) -> &'a str {...}


Lifetime Annotations in Method Definitions

// 구조체에 수명이 명시되어 있다면 메서드에도 명시해야 함
impl<'a> ImportantExcerpt<'a> {
    fn level(&self) -> i32 {
        3
    }
}

// 반환값의 수명이 self와 동일하다면 따로 명시해주지 않아도 괜찮음
impl<'a> ImportantExcerpt<'a> {
    fn announce_and_return_part(&self, announcement: &str) -> &str {
        println!("Attention please: {}", announcement);
        self.part
    }
}

// 따로 명시가 필요한 경우
impl<'a> ImportantExcerpt<'a> {
    fn announce_and_return_part<'b>(&self, announcement: &'b str) -> &'b str {
        println!("Attention please: {}", announcement);
        announcement
    }
}


The Static Lifetime

let s: &'static str = "I have a static lifetime.";


모두 합치기: 제네릭 타입 인자, 트레이트 경계, 수명

use std::fmt::Display;

fn longest_with_an_announcement<'a, T>(
    x: &'a str,
    y: &'a str,
    ann: T,
) -> &'a str
where
    T: Display,
{
    println!("Announcement! {}", ann);
    if x.len() > y.len() {
        x
    } else {
        y
    }
}