wqpw_blog

= =

View on GitHub
7 October 2019

Rust简单整理(c18-c20)

by wqpw

基于官方教程《The Rust Programming Language》

18. Patterns and Matching

fn main() {
    //complex requirments
    let favorite_color: Option<&str> = None;
    let is_tuesday = false;
    let age: Result<u8, _> = "34".parse();
    if let Some(color) = favorite_color {
        println!("Using your favorite color, {}, as the background", color);
    } else if is_tuesday {
        println!("Tuesday is green day!");
    } else if let Ok(age) = age {
        if age > 30 {
            println!("Using purple as the background color");
        } else {
            println!("Using orange as the background color");
        }
    } else {
        println!("Using blue as the background color");
    }
    let mut stack = Vec::new();
    stack.push(1);
    stack.push(2);
    stack.push(3);
    //refutable
    while let Some(top) = stack.pop() {
        println!("{}", top);
    }
    let v = vec!['a', 'b', 'c'];
    //irrefutable 
    for (index, value) in v.iter().enumerate() {
        println!("{} is at index {}", value, index);
    }
    let point = (3, 5); // irrefutable
    print_coordinates(&point);
    all_pattern();
//at binding @
//Using @ lets us test a value and save it 
//in a variable within one pattern.
    enum Message {
        Hello { id: i32 },
    }
    let msg = Message::Hello { id: 5 };
    match msg {
        Message::Hello { id: id_variable @ 3...7 } => {
            println!("Found an id in range: {}", id_variable)
        },
        Message::Hello { id: 10...12 } => {
            println!("Found an id in another range")
        },
        Message::Hello { id } => {
            println!("Found some other id: {}", id)
        },
    }
}
//match arms must use refutable patterns, 
//except for the last arm
fn print_coordinates(&(x, y): &(i32, i32)) {
    println!("Current location: ({}, {})", x, y);
}
fn all_pattern() {
    /*
    //Matching Literals
    let x = 1;
    match x {
        1 => println!("one"),
        2 => println!("two"),
        3 => println!("three"),
        _ => println!("anything"),
    }
    //Matching Named Variables
    let x = Some(5);
    let y = 10;
    match x { //new scope, new y. shadow x
        Some(50) => println!("Got 50"),
        Some(y) => println!("Matched, y = {:?}", y),
        _ => println!("Default case, x = {:?}", x),
    }
    println!("at the end: x = {:?}, y = {:?}", x, y);
    //using the | syntax, which means or
    let x = 1;
    match x {
        1 | 2 => println!("one or two"),
        3 => println!("three"),
        _ => println!("anything"),
    }
    //The ... syntax allows us to match to an inclusive range of values
    let x = 5;
//only allowed with numeric values or char values
    match x {
        1...5 => println!("one through five"),
        _ => println!("something else"),
    }
    let x = 'c';
    match x {
        'a'...'j' => println!("early ASCII letter"),
        'k'...'z' => println!("late ASCII letter"),
        _ => println!("something else"),
    }
    //destructing struct
    struct Point {
        x: i32,
        y: i32,
    }
    let p = Point { x: 0, y: 7 };
    let Point { x: a, y: b } = p;
    assert_eq!(0, a);
    assert_eq!(7, b);
    let Point { x, y } = p;
    assert_eq!(0, x);
    assert_eq!(7, y);
    let p = Point { x: 0, y: 7 };
    match p {
        Point { x, y: 0 } => println!("On the x axis at {}", x),
        Point { x: 0, y } => println!("On the y axis at {}", y),
        Point { x, y } => println!("On neither axis: ({}, {})", x, y),
    }
    //enum
    enum Message {
        Quit,
        Move { x: i32, y: i32 },
        Write(String),
        ChangeColor(i32, i32, i32),
    }
    let msg = Message::ChangeColor(0, 160, 255);
    match msg {
        Message::Quit => {
            println!("The Quit variant has no data to destructure.")
        },
        Message::Move { x, y } => {
            println!(
                "Move in the x direction {} and in the y direction {}",
                x,
                y
            );
        }
        Message::Write(text) => println!("Text message: {}", text),
        Message::ChangeColor(r, g, b) => {
            println!(
                "Change the color to red {}, green {}, and blue {}",
                r,
                g,
                b
            )
        }
    }
    //nested!
    enum Color {
        Rgb(i32, i32, i32),
        Hsv(i32, i32, i32),
    }
    let msg = Message::ChangeColor(Color::Hsv(0, 160, 255));
    match msg {
        Message::ChangeColor(Color::Rgb(r, g, b)) => {
            println!(
                "Change the color to red {}, green {}, and blue {}",
                r,
                g,
                b
            )
        },
        Message::ChangeColor(Color::Hsv(h, s, v)) => {
            println!(
                "Change the color to hue {}, saturation {}, and value {}",
                h,
                s,
                v
            )
        }
        _ => ()
    }
    //struct and tuples
    let ((feet, inches), Point {x, y}) = ((3, 10), Point { x: 3, y: -10 });
    //ignore
    fn foo(_: i32, y: i32) {
        println!("This code only uses the y parameter: {}", y);
    }
    foo(3, 4);
    let mut setting_value = Some(5);
    let new_setting_value = Some(10);
    match (setting_value, new_setting_value) {
        (Some(_), Some(_)) => {
            println!("Can't overwrite an existing customized value");
        } //output
        _ => {
            setting_value = new_setting_value;
        } //then = 10
    }
    println!("setting is {:?}", setting_value);
    let numbers = (2, 4, 8, 16, 32);
    match numbers {
        (first, _, third, _, fifth) => {
            println!("Some numbers: {}, {}, {}", first, third, fifth)
        },
    }
    //not warn unused variables
    let _x = 5;
    //_x still binds the value to the variable, 
    //whereas _ doesn’t bind at all
    //.. ignore the rest
    struct Point {
        x: i32,
        y: i32,
        z: i32,
    }
    let origin = Point { x: 0, y: 0, z: 0 };
    match origin {
        Point { x, .. } => println!("x is {}", x),
    }
    //.. will expand to as many values as it needs to be
    let numbers = (2, 4, 8, 16, 32);
    match numbers {
        (first, .., last) => {
            println!("Some numbers: {}, {}", first, last);
        },
    }
    //Match Guards!
    let num = Some(4);
    match num {
        Some(x) if x < 5 => println!("less than five: {}", x),
        Some(x) => println!("{}", x),
        None => (),
    }
    let x = Some(5);
    let y = 10;
    match x {
        Some(50) => println!("Got 50"),
        Some(n) if n == y => println!("Matched, n = {:?}", n),
        _ => println!("Default case, x = {:?}", x),
    }
    println!("at the end: x = {:?}, y = {:?}", x, y);
*/
    let x = 4;
    let y = false;
//only matches if the value of x is equal to 4, 5, or 6 
//and if y is true
    match x {
        4 | 5 | 6 if y => println!("yes"), //(4 | 5 | 6) if y => ...
        _ => println!("no"),
    }
}

19. Advanced Features

//r_unsafe.rs
/*
unsafe:
1.Dereference a raw pointer
2.Call an unsafe function or method
3.Access or modify a mutable static variable
4.Implement an unsafe trait
provide a safe interface to unsafe code
*/
extern "C" {
    fn abs(input: i32) -> i32;
}
//C's Application Binary Interface ABI
static HELLO: &str = "HELLO";
//mutable static variables is unsafe
static mut COUNTER: u32 = 0;
fn add_to_count(inc: u32) {
    unsafe {
        COUNTER += inc;
    }
}
//A trait is unsafe when at least one of its methods
//has some invariant that the compiler can’t verify.
unsafe trait Foo {}
unsafe impl Foo for i32 {}
fn main() {
    //raw pointer. * is part of the type name
    let mut num = 5;
    let r1 = &num as *const i32; //immutable pointer
    let r2 = &mut num as *mut i32; //can change num
    unsafe {
        println!("{} {}", *r1, *r2);
    }
    //unsafe func
    unsafe fn dangerous() {}
    unsafe {
        dangerous();
    }
    let mut v = vec![1, 2, 3, 4, 5, 6];
    let r = &mut v[..];
    let (a, b) = r.split_at_mut(3);
    assert_eq!(a, &mut [1, 2, 3]);
    assert_eq!(b, &mut [4, 5, 6]);
    unsafe {
        println!("{}", abs(-5));
    }
}
use std::slice;
fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
    let len = slice.len();
    let ptr = slice.as_mut_ptr();
    assert!(mid <= len); //gurantee safe!
    unsafe {
        (slice::from_raw_parts_mut(ptr, mid),
         slice::from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
    }
}

//ad_trait.rs
pub trait Iterator {
    type Item; //associated type
    fn next(&mut self) -> Option<Self::Item>;
}
use std::ops::Add;
struct Point {
    x: i32,
    y: i32,
} //Operator Overloading
/*
trait Add<RHS=Self> { default type parameters
    type Output;      right hand side rhs
    fn add(self, rhs: RHS) -> Self::Output;
}
*/
impl Add for Point {
    type Output = Point;
    fn add(self, other: Point) -> Point {
        Point {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}
struct Millimeters(u32);
struct Meters(u32);
impl Add<Meters> for Millimeters { //dif type +
    type Output = Millimeters;
    fn add(self, other: Meters) -> Millimeters {
        Millimeters(self.0 + (other.0 * 1000))
    }
}
trait Pilot {
    fn fly(&self); //method
}
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*");
    }
}
trait Animal {
    fn baby_name() -> String; //associated function dont have &self
}
struct Dog;
impl Dog {
    fn baby_name() -> String {
        String::from("Spot")
    }
}
impl Animal for Dog {
    fn baby_name() -> String {
        String::from("puppy")
    }
}
use std::fmt;
//OutlinePrint trait will work only for types that 
//also implement Display and provide the functionality 
//that OutlinePrint needs
trait OutlinePrint: fmt::Display {
    fn outline_print(&self) {
        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));
    }
}
impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}
//Newtype Pattern to Implement External Traits on External Types
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 person = Human;
    Pilot::fly(&person);
    Wizard::fly(&person);
    person.fly(); //Human::fly(&person);
    println!("A baby dog is called a {}", Dog::baby_name());
    //fully qualified syntax
    println!("A baby dog is called a {}", <Dog as Animal>::baby_name());
    //<Type as Trait>::function(receiver_if_method, next_arg, ...);
    let w = Wrapper(vec![String::from("hello"), String::from("world")]);
    println!("w = {}", w);
}

//ad_type.rs
fn main() {
    type Kilometers = i32;
    type Thunk = Box<dyn Fn() + Send + 'static>;
    let x: i32 = 5;
    let y: Kilometers = 5;
    println!("x + y = {}", x + y);
    type Result<T> = std::result::Result<T, std::io::Error>;
    //continue -> !
    //panic! -> !
    //loop {print!("and ever ");} -> !
    //DST dynamically sized types, or unsized types
    //we must always put values of dynamically sized types 
    //behind a pointer of some kind.
    //let s1: str = "Hello there!"; error
    //Every trait is a dynamically sized type 
    //we can refer to by using the name of the trait.
    let answer = do_twice(add_one, 5);
    println!("The answer is: {}", answer);
    let list_of_numbers = vec![1, 2, 3];
    let list_of_strings: Vec<String> = list_of_numbers
        .iter()
        .map(ToString::to_string)
        .collect();
    enum Status {
        Value(u32),
        Stop,
    }
    let list_of_statuses: Vec<Status> =
        (0u32..20)
        .map(Status::Value) //using the initializer function of Status::Value
        .collect();
    //you can’t return closures directly.
    //fn returns_closure() -> Fn(i32) -> i32
    //Rust doesn’t know how much space it will need to store the closure. 
    fn returns_closure() -> Box<dyn Fn(i32) -> i32> { //fine
        Box::new(|x| x + 1)
    }
}
//The Never Type that Never Returns
fn bar() -> ! {
    panic!("233");
}
/*
impl<T> Option<T> {
    pub fn unwrap(self) -> T {
        match self {
            Some(val) => val,
            None => panic!("called `Option::unwrap()` on a `None` value"),
        }
    }
}
*/
fn generic<T: ?Sized>(t: &T) {
    //T may or may not be Sized
}
//function pointer!
//fn type is called a function pointer.
fn add_one(x: i32) -> i32 {
    x + 1
}
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
    f(arg) + f(arg)
}

20. Final Project: Building a Multithreaded Web Server

//lib.rs
use std::thread;
use std::sync::mpsc;
use std::sync::Arc;
use std::sync::Mutex;
enum Message {
    NewJob(Job),
    Terminate,
}
pub struct ThreadPool {
    workers: Vec<Worker>,
    sender: mpsc::Sender<Message>,
}
trait FnBox {
    fn call_box(self: Box<Self>);
}
impl<F: FnOnce()> FnBox for F {
    fn call_box(self: Box<F>) {
        (*self)()
    }
}
type Job = Box<dyn FnBox + Send + 'static>;
impl ThreadPool {
    pub fn new(size: usize) -> ThreadPool {
        assert!(size > 0);
        let (sender, receiver) = mpsc::channel();
        let receiver = Arc::new(Mutex::new(receiver));
        let mut workers = Vec::with_capacity(size);
        for id in 0..size {
            workers.push(Worker::new(id, Arc::clone(&receiver)));
        }
        ThreadPool {
            workers,
            sender,
        }
    }
    pub fn execute<F>(&self, f: F)
        where
            F: FnOnce() + Send + 'static
    {
        let job = Box::new(f);
        self.sender.send(Message::NewJob(job)).unwrap();
    }
}
impl Drop for ThreadPool {
    fn drop(&mut self) {
        println!("Sending terminate message to all workers.");
        for _ in &mut self.workers {
            self.sender.send(Message::Terminate).unwrap();
        }
        println!("Shutting down all workers.");
        for worker in &mut self.workers {
            println!("Shutting down worker {}", worker.id);
            if let Some(thread) = worker.thread.take() {
                thread.join().unwrap();
            }
        }
    }
}
struct Worker {
    id: usize,
    thread: Option<thread::JoinHandle<()>>,
}
impl Worker {
    fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Message>>>) ->
        Worker {
        let thread = thread::spawn(move ||{
            loop {
                let message = receiver.lock().unwrap().recv().unwrap();
                match message {
                    Message::NewJob(job) => {
                        println!("Worker {} got a job; executing.", id);

                        job.call_box();
                    },
                    Message::Terminate => {
                        println!("Worker {} was told to terminate.", id);
                        break;
                    },
                }
            }
        });
        Worker {
            id,
            thread: Some(thread),
        }
    }
}
//main.rs
use hello::ThreadPool;
use std::io::prelude::*;
use std::net::TcpListener;
use std::net::TcpStream;
use std::fs;
use std::thread;
use std::time::Duration;
fn main() {
    let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
    let pool = ThreadPool::new(4);
    for stream in listener.incoming().take(2) {
        let stream = stream.unwrap();
        pool.execute(|| {
            handle_connection(stream);
        });
    }
    println!("Shutting down.");
}
fn handle_connection(mut stream: TcpStream) {
    let mut buffer = [0; 512];
    stream.read(&mut buffer).unwrap();
    let get = b"GET / HTTP/1.1\r\n";
    let sleep = b"GET /sleep HTTP/1.1\r\n";

    let (status_line, filename) = if buffer.starts_with(get) {
        ("HTTP/1.1 200 OK\r\n\r\n", "hello.html")
    } else if buffer.starts_with(sleep) {
        thread::sleep(Duration::from_secs(5));
        ("HTTP/1.1 200 OK\r\n\r\n", "hello.html")
    } else {
        ("HTTP/1.1 404 NOT FOUND\r\n\r\n", "404.html")
    };
    let contents = fs::read_to_string(filename).unwrap();
    let response = format!("{}{}", status_line, contents);
    stream.write(response.as_bytes()).unwrap();
    stream.flush().unwrap();
}
tags: blog