From a7536995ccdb8690172c94eb65a9cf4895fd8a07 Mon Sep 17 00:00:00 2001 From: andy Date: Mon, 21 Jun 2021 17:13:01 +0100 Subject: [PATCH] added more examples --- .gitignore | 1 + Cargo.lock | 2 +- Cargo.toml | 2 +- src/collections.rs | 62 ++++++++++++++++ src/iterate.rs | 3 +- src/lib.rs | 28 +++++++ src/lifetimes.rs | 35 +++++++++ src/macros.rs | 14 ++++ src/main.rs | 178 ++++++++++++++++++++++++++++++--------------- src/pointers.rs | 11 +++ src/structs.rs | 84 +++++++++++++++++++++ src/threads.rs | 57 +++++++++++++++ 12 files changed, 415 insertions(+), 62 deletions(-) create mode 100644 src/collections.rs create mode 100644 src/lib.rs create mode 100644 src/lifetimes.rs create mode 100644 src/pointers.rs create mode 100644 src/structs.rs create mode 100644 src/threads.rs diff --git a/.gitignore b/.gitignore index ea8c4bf..1385427 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +hello.txt diff --git a/Cargo.lock b/Cargo.lock index 2b5c008..b5367a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,7 +71,7 @@ dependencies = [ ] [[package]] -name = "rusty-playground" +name = "rustyplayground" version = "0.1.0" dependencies = [ "rand", diff --git a/Cargo.toml b/Cargo.toml index 4c41f29..8931722 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "rusty-playground" +name = "rustyplayground" version = "0.1.0" authors = ["aj "] edition = "2018" diff --git a/src/collections.rs b/src/collections.rs new file mode 100644 index 0000000..4dcbc7d --- /dev/null +++ b/src/collections.rs @@ -0,0 +1,62 @@ +use std::collections::HashMap; + +// tuples and arrays +// both stack-based +pub fn compound() { + let tup = (500, 'a'); + let (_, second) = tup; + println!("tuple: {}/{}", tup.0, second); + + // all of same type, [u8; 4] = 4 u8 types + let _arr: [u8; 4] = [1, 2, 3, 4]; + let repeater = [3; 5]; // broadcasts 5 elements of 3 + println!("Retrieving from array: {}", repeater[3]); +} + +pub fn vectors() { + let v: Vec = Vec::new(); + let mut v = vec![1, 2, 3, 4]; + v.push(5); + + let mut v: Vec<_> = v.iter().map(|x| x + 1).collect(); + + println!("{:?}", v); + println!("2nd element is {}, {}", + &v[1], // will crash with index-out-of-bounds + v.get(1).unwrap() // get an option to handle gracefully + ); + + for i in &mut v{ + *i += 1; + println!("item: {}", i); + } +} + +pub fn hash() { + let mut map = HashMap::new(); + + map.insert("a".to_string(), 5); + + map.insert("b".to_string(), 6); + map.insert("b".to_string(), 7); // overwrites + + // map.insert("c".to_string(), 10); + map.entry("c".to_string()).or_insert(8); + + println!("{:?}", map); + + for (key, val) in map { + println!("{}: {}", key, val); + } + + let text = "hello world wonderful world"; + + let mut map = HashMap::new(); + + for word in text.split_whitespace() { + let count = map.entry(word).or_insert(0); + *count += 1; + } + + println!("{:?}", map); +} \ No newline at end of file diff --git a/src/iterate.rs b/src/iterate.rs index 6555c3a..462a070 100644 --- a/src/iterate.rs +++ b/src/iterate.rs @@ -12,7 +12,8 @@ mod iterate { impl Iterator for Counter { type Item = u32; - + + /// Get next item from the iterator fn next(&mut self) -> Option { if self.count < 5 { self.count += 1; diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..c8f0350 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,28 @@ +//! Crate documentation + +/// Print hello world to the screen +/// # Title +pub fn print_hello(){ + println!("Hello World!"); +} + +/// Return sum of input +/// +/// # Examples +/// ``` +/// let z = rustyplayground::add(1, 2); +/// +/// assert_eq!(3, z) +/// ``` +pub fn add(x: isize, y: isize) -> isize { + x + y +} + +pub mod new_mod { + //! # Documented module + //! + + pub fn fun() { + + } +} \ No newline at end of file diff --git a/src/lifetimes.rs b/src/lifetimes.rs new file mode 100644 index 0000000..9781ea5 --- /dev/null +++ b/src/lifetimes.rs @@ -0,0 +1,35 @@ + +// declare lifetime after function name like generic type +// both parameters have same lifetime and must be alive when returned +fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { + if x.len() > y.len() { + x + } else { + y + } +} +// doesn't change lifetimes of parameters, just annotates enough +// that the compiler can reject stuff that won't work + +// structs can have reference members +// annotate with lifetimes to ensure struct doesn't outlive reference +struct ImportantExcerpt<'a> { + part: &'a str, +} + +// generic types, trait bounds and lifetimes +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 + } +} \ No newline at end of file diff --git a/src/macros.rs b/src/macros.rs index 4d48019..b62811c 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -6,6 +6,20 @@ macro_rules! log { } } +#[macro_export] +macro_rules! simple_vec { + // comma is literal, comma indicates zero or more + ( $( $x:expr ),* ) => { + { + let mut temp_vec = Vec::new(); + $( + temp_vec.push($x); + )* + temp_vec + } + }; +} + #[macro_export] macro_rules! expr_stringer { // This macro takes an expression of type `expr` and prints diff --git a/src/main.rs b/src/main.rs index 34611e9..a7038f2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,20 +1,32 @@ -use std::io; use std::cmp::Ordering; +use std::fs::File; +use std::io::{self, Read, ErrorKind}; use rand::Rng; +// use rustyplayground; mod iterate; mod macros; +mod structs; +mod collections; +mod threads; fn main() { - basics(); - compare(); - loops(); - vars(); - compound(); + // rustyplayground::print_hello(); + // basics(); + // compare(); + // loops(); + // vars(); + // collections::compound(); + // collections::vectors(); + collections::hash(); + threads::start_threads(); + threads::thread_channel(); - println!("testing returns: {}", returning(2)); - strings(); - nullables(); + // println!("testing returns: {}", returning(2)); + // strings(); + // nullables(); + + nested_error_matching(); } fn basics() { @@ -47,9 +59,9 @@ fn basics() { let r_num = rand::thread_rng().gen_range(1, 101); println!("random number: {}", r_num); - let vec = build_vector3(1, 2, 3); + let vec = structs::build_vector3(1, 2, 3); println!("Vector: {}/{}/{}", vec.x, vec.y, vec.z); - let vec2 = update_x(vec); + let vec2 = structs::update_x(vec); println!("Vector2: {:#?}", vec2) } @@ -110,16 +122,6 @@ fn vars() { let _f = 2.0; // defaults to 64 bit } -fn compound() { - let tup = (500, 'a'); - let (_, second) = tup; - println!("tuple: {}/{}", tup.0, second); - - let _arr: [u8; 4] = [1, 2, 3, 4]; - let repeater = [3; 5]; // stretches to 5 elements of 3 - println!("Retrieving from array: {}", repeater[3]); -} - fn returning(input: i32) -> i32 { let _stuff = 0; @@ -132,51 +134,28 @@ fn returning(input: i32) -> i32 { fn strings() { let mut s = String::from("hello"); + let s2 = "world!".to_string(); + let s3 = String::from("hello"); + + // cannot [] index strings due to utf-8 encoding + s.push_str(", world!"); - println!("Sliced: {}", &s[4..8]); -} + println!("Sliced: {}", &s[4..8]); // slice + println!("Appended: {}", s3 + " 2"); // takes ownership of s3 + println!("{}", + format!("{} {}", s, s2) + ); -#[derive(Debug)] -struct Vector3 { - x: i32, - y: i32, - z: i32, -} - -impl Vector3 { - fn dot(&self, other: &Vector3) -> i32 { - self.x * other.x - + - self.y * other.y - + - self.z * other.z + let s4 = "abcd".to_string(); + for i in s4.chars() { + println!("{}", i); } -} -fn build_vector3(x: i32, y: i32, z: i32) -> Vector3 { - Vector3 { - x, y, z + for i in s4.bytes() { + println!("{}", i); } } -fn update_x(vec: Vector3) -> Vector3 { - Vector3 { - x: 5, - ..vec - } -} - -enum ColourChannel { - Red, - Green, - Blue -} - -enum IpAddr { - V4(u8, u8, u8, u8), - V6(String), -} - fn nullables() { let _some_number = Some(5); let _some_string = Some("a string"); @@ -184,7 +163,71 @@ fn nullables() { let _absent_number: Option = None; } +fn nested_error_matching() { + let f = File::open("hello.txt"); + + // .unwrap() get inner value or panic + // .expect() as above but with custom error message + + let f = match f { + Ok(file) => file, + Err(error) => match error.kind() { + ErrorKind::NotFound => match File::create("hello.txt") { + Ok(fc) => fc, + Err(e) => panic!("Problem creating the file: {:?}", e), + }, + other_error => { + panic!("Problem opening the file: {:?}", other_error) + } + }, + }; + + let f = File::open("hello.txt").unwrap_or_else(|error| { + if error.kind() == ErrorKind::NotFound { + File::create("hello.txt").unwrap_or_else(|error| { + panic!("Problem creating the file: {:?}", error); + }) + } else { + panic!("Problem opening the file: {:?}", error); + } + }); +} + +fn propagate_err() -> Result { + let f = File::open("hello.txt"); + + let mut f = match f { + Ok(file) => file, + Err(e) => return Err(e), + }; + + let mut s = String::new(); + + match f.read_to_string(&mut s) { + Ok(_) => Ok(s), + Err(e) => Err(e), + } +} + +fn propagate_err_operator() -> Result { + let mut f = File::open("hello.txt")?; + let mut s = String::new(); + f.read_to_string(&mut s)?; // continue if ok, return error if not, convert to return type if required + Ok(s) +} + +fn propagate_err_operator_shorter() -> Result { + + // can also be done with fs::read_to_string() + + let mut s = String::new(); + File::open("hello.txt")?.read_to_string(&mut s)?; // continue if ok, return error if not, convert to return type if required + Ok(s) +} + + #[cfg(test)] +// #[warn(unused_imports)] mod tests { use super::*; @@ -192,4 +235,21 @@ mod tests { fn test1() { assert_eq!(2, 1 + 1); } + + #[ignore] + #[test] + #[should_panic(expected = "index out of bounds")] // check that panic message is substring of actual + fn test_panic() { + let arr = vec![1, 2, 3]; + arr[4]; + } + + #[test] + fn test_result() -> Result<(), String> { + if 2 + 2 == 4 { + Ok(()) + } else { + Err("Error".to_string()) + } + } } \ No newline at end of file diff --git a/src/pointers.rs b/src/pointers.rs new file mode 100644 index 0000000..65cc2d1 --- /dev/null +++ b/src/pointers.rs @@ -0,0 +1,11 @@ + +// indireaction of box lets list be a fixed size +enum List { + Cons(i32, Box), + Nil, +} + +fn box_ptr() { + let b = Box::new(5); // implements deref and drop + println!("b = {}", b); +} \ No newline at end of file diff --git a/src/structs.rs b/src/structs.rs new file mode 100644 index 0000000..c32f5ca --- /dev/null +++ b/src/structs.rs @@ -0,0 +1,84 @@ +// and enums + +use std::fmt::Display; + +pub trait Euclidean { + fn cross(); + fn magnitude() { + println!("Hello World"); + } +} + +#[derive(Debug)] +pub struct Vector3 { + pub x: i32, + pub y: i32, + pub z: i32, +} + +impl Vector3 { + fn dot(&self, other: &Vector3) -> i32 { + self.x * other.x + + + self.y * other.y + + + self.z * other.z + } +} + +impl Euclidean for Vector3 { + fn cross() {} +} + +// FIELD INIT SHORTHAND +pub fn build_vector3(x: i32, y: i32, z: i32) -> Vector3 { + Vector3 { + x, y, z + } +} + +// STRUCT UPDATE SYNTAX +pub fn update_x(vec: Vector3) -> Vector3 { + Vector3 { + x: 5, + ..vec + } +} + +// use trait as a parameter type +pub fn compound_mag(x: &impl Euclidean, + y: &(impl Euclidean + Display)) // multiple required traits +{ + +} + +// above is sugar for below, restrictions on generic types +pub fn compound_mag_long(x: &T) + -> impl Display // specify just traits of a return type +{ + 5 // for display trait +} + +// use where for easier reading +pub fn compound_mag_where(x: &T) + where T: Euclidean + Display { +} + +enum ColourChannel { + Red, + Green, + Blue +} + +#[derive(Debug)] +enum IpAddr { + V4(u8, u8, u8, u8), + V6(String), +} + +// can add methods to enums as well +impl IpAddr { + fn print(&self) { + println!("{:?}", self); + } +} \ No newline at end of file diff --git a/src/threads.rs b/src/threads.rs new file mode 100644 index 0000000..f15f169 --- /dev/null +++ b/src/threads.rs @@ -0,0 +1,57 @@ +use std::thread; +use std::time::Duration; +use std::sync::mpsc; + +// 1:1 threads +pub fn start_threads() { + + let v = vec![1, 2, 3, 4]; + + // use move to transfer data into new thread + let handle = thread::spawn(move || { + println!("{:?}", v); + for i in v { + println!("{} from separate thread", i); + } + }); + + handle.join().unwrap(); + thread::sleep(Duration::from_millis(5)); +} + +pub fn thread_channel() { + + let (tx, rx) = mpsc::channel(); + + // use move to transfer data into new thread + thread::spawn(move || { + tx.send("Hello message!".to_string()).unwrap(); + }); + + let rec = rx.recv().unwrap(); + println!("{}", rec); + + // MULTIPLE + + let (tx, rx) = mpsc::channel(); + + // use move to transfer data into new thread + thread::spawn(move || { + let vals = vec![ + String::from("h"), + String::from("e"), + String::from("l"), + String::from("l"), + String::from("o"), + ]; + + for val in vals { + tx.send(val).unwrap(); + thread::sleep(Duration::from_millis(200)); + } + }); + + for rec in rx { + println!("{}", rec); + } +} \ No newline at end of file