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();
}