CS152
Chris Pollett
Oct 6, 2021
fn main() { let s = "hello world"; println!("{}", s.len()); // 11 let s2 = ""; println!("{}", s.is_empty()); // false println!("{}", s2.is_empty()); // true //other useful boolean methods: starts_with, ends_with, contains //similar to contains, find(some_string) can be used to find position let s2 = "!!!"; //faking concatenation let s3 = format!("{}{}", s, s2); //hello world!!! println!("{}", s3); let s4 = " yoyoyo "; println!("{}", s4.trim());//yoyoyo (no spaces) //also has trim_left, trim_right, strip_prefix(some_string), // strip_suffix(some_string) //a u8 bytes string slices can be extracted // from a string using get(lo..hi) let s = s.replace("hello", "howdy"); println!("{}", s); //howdy world // also has repeat, to_lowercase, to_uppercase let v = s.split("w"); // also has lines() to split based on end of lines for elt in v { //notice Rust support for in loops print!("{} ", elt); //ho dy orld } let i:u8 = "17".parse().unwrap(); //alternatively, let i = "17".parse::<u8>();.unwrap(); // ::<some_type> called a turbo fish let i = i + 1; println!("{}", i);//18 }
let /* mut */ some_var : [some_type; some_size] = ... ; //[initial members] or [initial_value; some_size]
let arr:[i32; 5] = [0,1,2,3,4]; let mut arr2:[u8; 100] = [0; 100]; //100 u8's all with initial value 0 let b = [[1, 0, 1], [0, 1, 0]]; //type inference +2D array
println!("arr[3] = {} b[1][1]={}", arr[3], b[1][1]); arr2[7] = 128; for elt in arr2 { println!("{}", elt); } println!("{:?}", arr);//[0, 1, 2, 3, 4] //{:?} is debug output format //{:#?} is pretty print debug output format println!("The length of arr2 is: {}", arr2.len());
fn main() { let tup1: (i8, f64, u8) = (-25, 6.2, 1); let tup2 = (100, -1.2, 9); // works by type inference; let (a, b, c) = tup1; //one way to get elements out //if don't want all components, could do expressions like (_, b, _) = println!("{} {} {}", a, b, c); println!("{}", tup2.2); // 9 }
let hi = "Hi there!";could be annotated with types as:
let hi: &'static str = "Hello, world!";The 'static indicates that it is directly stored in the binary file and persists for the lifetime of the program.
let mut s = String::from("hello"); s.push_str(" world"); println!("{}", s);
{ // s, s2 not valid let s = "hi there"; // s is valid from here to the end of the block //s2 not valid here let mut s2 = String::from("hello"); //s2 valid here to end of block //... more code where s, s2 are valid } // s, s2 no longer valid
let x = 20; let y = x;Rust makes new space for the second variable `y` on the stack and copies the value 20 into this space. This is called a copy operation, and it is valid for all integer, Boolean, char types and tuples made from them.
let s1 = String::from("hi there"); let s2 = s1;
let s1 = String::from("hi there"); let s2 = s1.clone(); // if had let s2 = s1; instead, next line would not work println!("s1 = {}, s2 = {}", s1, s2);
fn main() { let x = 5; makes_copy(x); println!("x is {}", x); //okay since x wasn't invalidated let s = String::from("hi there"); takes_ownership(s); println!("s is {}", s); //not okay since s was invalidated }
fn main() { let s = String::from("hi there"); let s2 = takes_ownership_and_gives_back(s); println!("s2 is {}", s2); / okay as s2 get ownership back from function } fn takes_ownership_and_gives_back(a_string:String) -> String { a_string; }
fn main() { let s = String::from("hi there"); let len= compute_len(&s); println!("'{}' has length {}", s, len); } fn compute_len(s: &String) -> usize { s.len() }
fn main() { let s = String::from("hi"); change(&s); } fn change(a_string: &String) { a_string.push_str(" there"); // will give compile error }
fn main() { let mut s = String::from("hi"); change(&mut s); } fn change(a_string: &mut String) { a_string.push_str(" there"); // works! }
fn main() { let mut s = String::from("hi"); let r1 = &mut s; let r2 = &mut s; // second active mutable ref to s }
let s = String::from("hello world"); let hello = &s[0..5]; //refers to the first five u8 bytes of s // could have written &s[..5]; which refers to the start through 5 byte let world = &s[6..11]; //refers to the last five u8 bytes of s // could have written &s[6..]; which refers to position 6 to end // &s[..] corresponds to a slice of the whole string let a = [1,2,3,4,5]; let two_three = &a[1..2]; // [2,3] let elts_from_pos_three_on = &a[3..]; // [4,5]
fn first_word(s: &String) -> &str { let bytes = s.as_bytes(); for (i, &item) in bytes.iter().enumerate() { if item == b' ' { //b' ' is a u8 literal for ASCII space return &s[0..i]; } } }
enum MyEnumsName { LABEL1, LABEL2, ... }
#[allow(dead_code)] //Rust attribute (like C pragma) //so don't get warning below for paths don't use //general format is: #[attribute(some_value)] enum MyEvent { JUMP, SQUAT, KEY(char), } fn main() { let _x = MyEvent::JUMP; //putting _ in front of var name //suppresses unused warning let y = MyEvent::KEY('a'); let z = match y { MyEvent::KEY(x) => x, _ => ' ', //catch all case }; println!("{}", z); // 'a' }
use MyEvent::*; fn main() { let _x = JUMP; //putting _ in front of var name //suppresses unused warning let y = KEY('a'); let z = match y { KEY(x) => x, _ => ' ', }; println!("{}", z); // 'a' }
enum Option<T> { Some(T), None }
fn main() { let a = [Some(4), Some(6), None, Some(6)]; for elt in a { match elt { Some(x) => println!("{}", x), None => println!("No Value"), } } }
4 6 No Value 6
// struct definition struct struct_name { property_name1: data_type1, property_name2: data_type2, //... } // struct specific functions impl struct_name { fn method_name1() { // method body } fn method_name2() { // method body } //... }
fn main() { // init structs let person_1 = Person { name: String::from("Bob"), age: 5, //notice okay to have a comma even if no more members }; let person_2 = Person { name: String::from("Sally"), age: 2, }; // use method person_1.print_name(); person_2.print_name(); println!("Person 2 age:{}", person_2.age); println!("Person 2 is_old:{}", person_2.is_old()); } // define struct struct Person { name: String, age: u8, } // Person specific methods impl Person { fn print_name(&self) { println!("Name: {}", self.name); } fn is_old(&self) -> bool { self.age > 3 } }
impl Person { fn print_name(&self) { println!("Name: {}", self.name); } } impl Person { fn is_old(&self) -> bool { self.age > 3 } }
pub struct MyStruct { //MyStruct would be visible outside of the module pub field1: field_type1, // field1 also visible, //but only because both it and MyStruct are pub field2: field_type1, //field2 not visible ouside of module }
pub trait MyTraitName { fn traitMethod1(&self, /* other params*/) -> return_type1; fn traitMethod2(&self, /* other params*/) -> return_type2; //... }
pub struct MyStruct { pub field1: type1, pub field2: type2, //... } impl MyTraitName for MyStruct { fn traitMethod1(&self, /* other params*/) -> return_type1 { //code for traitMethod1 } fn traitMethod2(&self, /* other params*/) -> return_type2 { //code for traitMethod2 } //... }
[workspace] members = [ "name_of_package1", #lists which subfolder of workspace are managed packages "name_of_package2", //.. ] [dependencies] //could list common dependencies across packages.
cargo new name_of_package
cargo run -p package_name
cargo cleanor
cargo clean -p project_name
[dependencies] my_other_package = {path = "../my_other_package"}
my_remote_package = "0.2.71"
use my_other_package; use my_remote_package; fn main() { //code that uses items from my_other_package and my_remote_package }
+ . - Cargo.lock (non human edited) - tracks dependency packages downloaded and installed and what versions - Cargo.toml (human-editable) list name of package, version, external package dependencies, etc cargo update can be used to update dependencies + src - main.rs // if default crate is a binary this file is the main entry point - lib.rs // if default crate is a library this file is the base file + bin - single_file_executable.rs //name of additional crate + multi_files_executable //name of additional crate - main.rs - module_in_multi_files_executable.rs + benches // benchmark crate + examples // examples code crate + tests // unit tests and integration test crate + targets // only created if project not in a workspace, contains build artefacts
cargo new my_crate_name
cargo build --lib build packages library crate cargo build --bins name_of_crate_in_bin_folder cargo run --bin name_of_crate_in_bin_folder cargo build --benches cargo build --bench name_of_particular_bench // run versions of above cargo build --examples cargo build --example name_of_particular_bench // run version of above cargo build --tests cargo build --test name_of_particular_bench // run version of above
//as this module not pub, not visible outside of enclosing module mod submodule1 { //code of name_of_submodule1 fn not_visible_function() { //this function is not pub so not visible outside of submodule1 } } // module public so visible outside enclosing module pub mod submodule2 { pub fn some_function() { } pub mod subsubmodule { pub fn some_function() { println!("Hello from subsubmodule"); } } //rest of code of name_of_submodule2 } //Can refer to objects in modules by giving the nesting path separated by :: submodule2::some_function(); submodule2::subsubmodel::some_function;
pub mod foo;
pub fn foo() { println!("lots of foo!!"); }and the following in goo.rs:
pub fn gooey() { println!("very gooey!!"); }
mod goo; //make available the goo module to the contents of the current module pub mod sub; //make available the sub as pub module use sub::foo::*; //the keyword 'use' and the * here //allows us to write foo() for sub::foo::foo() below fn main() { println!("Hello, world!"); println!("yo"); foo(); goo::gooey(); }
use std::env; use std::fs; fn main() { let args: Vec<_> = env::args().collect(); if args.len() > 1 { let filename = &args[1]; let contents = fs::read_to_string(filename) .expect("Something went wrong reading the file"); println!("Here is the file:\n{}", contents); } else { println!("Need more arguments"); } }
use std::fs; fn main() { fs::write("bar.txt", "yummy chocolate bar") .expect("OOPS! Write didn't work"); }
use std::io; fn main() { println!("Enter a your name:"); let mut name = String::new(); io::stdin().read_line(&mut name). expect("Couldn't read line"); println!("Your name was: {}", name); }
fn main() { let mut v: Vec<i32> = Vec::new(); v.push(1); v.push(4); v.push(8); v.push(14); for elt in &v { //&v not v to avoid move print!("{} ", elt); // 1 4 8 14 } let x: &i32 = &v[2]; println!("\n{}", x); // 8 v[1] = 6; println!("{}", &v[1]); let w = vec![7, 8, 9]; //can also create vector this way match w.get(2) { Some(num) => println!("{}", num), //9 None => println!("Third elment does not exist"), } let mut months_days: HashMap= HashMap::new(); months_days.insert("January".to_string(), 31); months_days.insert("February".to_string(), 28); if months_days.contains_key("February") { println!("Has February"); } match months_days.get("March") { Some(days) => println!("March has: {}", days), None => println!("March is not in month_days"), } for (month, days) in &months_days { println!("Month {} has {} days", month, days); } }
cargo tests //-p package_name (if using a workspace) cargo tests name_of_test_function
use unit_experiment::return_one; fn main() { println!("This is what return_one() returns:{}", return_one()); }
/// Returns 1, but does it well /// /// Below is a unit test in a comment /// ``` /// let x = unit_experiment::return_one(); /// assert_eq!(x, 1); /// ``` pub fn return_one() -> u32 { return_two() / 2 } /// Returns 2, twice as well /// Notice this function is private /// fn return_two() -> u32 { 2 } #[cfg(test)] mod tests { use super::*; //to access enclosing module #[test] fn one_is_less_eq_two() { assert!(return_one() <= return_two()); } #[test] fn one_not_eq_two() { assert_ne!(return_one(), return_two()); } }
use unit_experiment::return_one; #[test] fn got_one() { assert_eq!(return_one(), 1); }
let x = 10 + 7;
let x = 10 + 7; //good let x = 10 + 7 ; //bad let x: &str = "hi there"; // good
x: & str //bad x: &str //good x: &mut str //good
pub struct Wrong { pub x : i32, pub foo: i64 } pub struct Right { pub x: i32, pub foo: i64 }
fn my_fun(param_1: type1, param_2: type3, //.. full line param_n: typen, /* another long line */) //these might be indented more than four spaces -> return_type { //code - note four spaces for indent of code }
fn bad() { println!("This is incorrect."); } struct Good { example: i32 } struct AlsoBad { example: i32 }