From 50bee77117c09499e5d0d1d2075d9a7bb1a0134d Mon Sep 17 00:00:00 2001 From: Braeden Sowinski Date: Fri, 18 Sep 2026 15:35:00 -0700 Subject: [PATCH] lecture 02 --- lectures/01/ownership.txt | 31 ++++++++++++++++++ lectures/02/Cargo.lock | 7 ++++ lectures/02/Cargo.toml | 6 ++++ lectures/02/data | 3 ++ lectures/02/errors.rs | 35 ++++++++++++++++++++ lectures/02/io.rs | 38 ++++++++++++++++++++++ lectures/02/src/main.rs | 13 ++++++++ lectures/02/src/strings.rs | 39 ++++++++++++++++++++++ lectures/02/src/structs.rs | 66 ++++++++++++++++++++++++++++++++++++++ lectures/02/src/tuples.rs | 15 +++++++++ lectures/02/src/vectors.rs | 47 +++++++++++++++++++++++++++ 11 files changed, 300 insertions(+) create mode 100644 lectures/01/ownership.txt create mode 100644 lectures/02/Cargo.lock create mode 100644 lectures/02/Cargo.toml create mode 100644 lectures/02/data create mode 100644 lectures/02/errors.rs create mode 100644 lectures/02/io.rs create mode 100644 lectures/02/src/main.rs create mode 100644 lectures/02/src/strings.rs create mode 100644 lectures/02/src/structs.rs create mode 100644 lectures/02/src/tuples.rs create mode 100644 lectures/02/src/vectors.rs diff --git a/lectures/01/ownership.txt b/lectures/01/ownership.txt new file mode 100644 index 0000000..7955a2c --- /dev/null +++ b/lectures/01/ownership.txt @@ -0,0 +1,31 @@ +- an object can have only 1 owner +- assignment/initialization either copies or moves the source + * if the source doesn't implement the Copy trait, it is moved to the + destination, i.e., ownership is transferred from the source to the + destination + * copy/move can also occur + - when passing by value into a function + - returning by value from a function + - when pattern-matching +- at any time, an object can have + EITHER 1 exclusive/mutable reference (&mut) to it + OR any number of shared references (&) to it +- we need to be aware of the scope of a reference: it starts from its + introduction up to and including the last time it is used (i.e., scope + of a reference is not lexical) +- if an object has any reference to it, it cannot be written to +- if an object has a exclusive reference to it, it cannot be read or written + (the object is "frozen") + +Copy trait: +- an array is Copy (i.e. implements the Copy trait) if its elements are Copy +- a tuple is Copy if its elements are Copy + +Basics: + let a = ...; + &a (OK), &mut a (NOT OK, a is not declared mut) + let mut a = ...; + &a, &mut a (BOTH OK, but not at the same time) + + let a = ...; // some type that doesn't implement Copy + let b = a; // a is moved to b diff --git a/lectures/02/Cargo.lock b/lectures/02/Cargo.lock new file mode 100644 index 0000000..b5298bd --- /dev/null +++ b/lectures/02/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "lec02" +version = "0.1.0" diff --git a/lectures/02/Cargo.toml b/lectures/02/Cargo.toml new file mode 100644 index 0000000..f49ad52 --- /dev/null +++ b/lectures/02/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "lec02" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/lectures/02/data b/lectures/02/data new file mode 100644 index 0000000..09e8ab7 --- /dev/null +++ b/lectures/02/data @@ -0,0 +1,3 @@ +hello world +hi +goodbye diff --git a/lectures/02/errors.rs b/lectures/02/errors.rs new file mode 100644 index 0000000..8ff6caa --- /dev/null +++ b/lectures/02/errors.rs @@ -0,0 +1,35 @@ +fn test1() { + let x = Some(32); + println!("{}", x.unwrap()); + // let x: Option = None; + // println!("{}", x.unrwap()); // panics + + let n = "123".parse::(); + println!("{n:?}") +} + +fn sqrt(x: f64) -> Option { + if (x < 0.0) { None } else { Some(f64::sqrt(x)) } +} + +fn ln_sqrt(x: f64) -> Option { + /* + match sqrt(x) { + Some(x) => f64::ln(x), + None => None, + } + + // OR + if let Some(x) = sqrt(x) { + Some(f64::ln(x)) + } else { + None + } + */ + + Some(f64::ln(sqrt(x)?)) +} + +fn main() { + test1(); +} diff --git a/lectures/02/io.rs b/lectures/02/io.rs new file mode 100644 index 0000000..d44065e --- /dev/null +++ b/lectures/02/io.rs @@ -0,0 +1,38 @@ +use std::env; +use std::fs::File; +use std::io::{self, BufRead}; + +fn read_lines() { + let mut line = String::new(); + + while let Ok(n) = io::stdin().read_line(&mut line) { + if n == 0 { + break; + } + print!("{line}"); + line.clear(); + } +} + +fn lines() -> io::Result> { + io::stdin().lines().collect() +} + +fn lines2() -> Vec { + io::stdin().lines().filter_map(|x| x.ok()).collect() +} + +fn file_lines(file: &str) -> io::Result> { + io::BufReader::new(File::open(file)?).lines().collect() +} + +fn main() { + let args: Vec<_> = env::args().skip(1).collect(); + println!("{args:?}"); + + if args.len() > 0 { + println!("{:?}", file_lines(&args[0])); + } else { + println!("{:?}", lines()); + } +} diff --git a/lectures/02/src/main.rs b/lectures/02/src/main.rs new file mode 100644 index 0000000..6138cfe --- /dev/null +++ b/lectures/02/src/main.rs @@ -0,0 +1,13 @@ +mod strings; +mod structs; +mod tuples; +mod vectors; + +fn main() { + println!("Hello, world!"); + + tuples::run(); + vectors::run(); + strings::run(); + structs::run(); +} diff --git a/lectures/02/src/strings.rs b/lectures/02/src/strings.rs new file mode 100644 index 0000000..22f749e --- /dev/null +++ b/lectures/02/src/strings.rs @@ -0,0 +1,39 @@ +pub fn run() { + println!("STRINGS"); + + let s1 = "hello"; // type &str + let s2 = String::from("world"); // type String + + print_str(s1); + // print_string(s1); // ERROR + // print_string_ref(s1); // ERROR + + print_str(&s2); // also accepts &String (Deref trait) + print_string_ref(&s2); + print_string(s2); // moves s2 + + let s = "नमस्ते"; + println!("{}", s.len()); // byte count -> 18 + // println!("{}", s[0]); // can't index string + println!("{:?}", &s[0..3]); // may panic if not at char boundary + for c in s.chars() { + println!("{c}"); + } + + println!("{}", s.chars().count()); + println!("{:?}", s.as_bytes()); +} + +// which version of string function should be used? +// CONCLUSION: function that takes &str is most flexible +fn print_str(s: &str) { + println!("{s}"); +} + +fn print_string(s: String) { + println!("{s}"); +} + +fn print_string_ref(s: &String) { + println!("{s}"); +} diff --git a/lectures/02/src/structs.rs b/lectures/02/src/structs.rs new file mode 100644 index 0000000..12604e8 --- /dev/null +++ b/lectures/02/src/structs.rs @@ -0,0 +1,66 @@ +use std::fmt; + +#[derive(Debug, Copy, Clone)] // derive the implementatoin of the Debug trait (like an interface) +struct Point(f64, f64); // tuple struct + +#[derive(Debug, Copy, Clone)] +pub struct Circle { + center: Point, + radius: f64, +} + +impl fmt::Display for Point { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "({}, {})", self.0, self.1) + } +} + +impl Circle { + // or you can specify -> Self + pub fn new(center: Point, radius: f64) -> Circle { + // Or you can specify self instead of Circle { + Circle { center, radius } // since names are the same, we dont need key: value pair + } + + pub fn area(&self) -> f64 { + std::f64::consts::PI * self.radius * self.radius + } + + pub fn scale(&mut self, factor: f64) { + self.radius *= factor; + } +} + +impl fmt::Display for Circle { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Circle: {} {}", self.center, self.radius) + } +} + +pub fn run() { + println!("STRUCTS"); + + let p = Point(1.0, 2.0); + println!("{} {}", p.0, p.1); + + let Point(x, y) = p; + println!("{x} {y}"); + + let c = Circle { + center: p, + radius: 1.0, + }; + println!("{c:?}"); + + let mut c = Circle::new(Point(0.0, 0.0), 1.0); + + println!("{}", c.area()); // area will automatically take reference + println!("{}", (&c).area()); // or you can specify manually + c.scale(2.0); + println!("{c:?}"); + println!("{}", c.area()); + + // after implementing Display trait + println!("{c}"); + let _s = format!("{c}"); // format uses Display trait, to convert to string +} diff --git a/lectures/02/src/tuples.rs b/lectures/02/src/tuples.rs new file mode 100644 index 0000000..3d425a4 --- /dev/null +++ b/lectures/02/src/tuples.rs @@ -0,0 +1,15 @@ +pub fn run() { + println!("TUPLES"); + + let t = (1, 3.14); + println!("{} {}", t.0, t.1); + println!("{t:?}"); // debug print + + let (x, y) = t; // pattern matching + println!("{x} {y}"); + println!("{:?}", swap(&t)); +} + +fn swap(t: &(i32, f64)) -> (f64, i32) { + (t.1, t.0) +} diff --git a/lectures/02/src/vectors.rs b/lectures/02/src/vectors.rs new file mode 100644 index 0000000..801a6b9 --- /dev/null +++ b/lectures/02/src/vectors.rs @@ -0,0 +1,47 @@ +pub fn run() { + println!("VECTORS"); + let v = vec![3, 2, 7, 6, 8]; // macro for creating vector with known type + println!("{v:?}"); + + for i in 0..v.len() { + println!("{}", v[i]); + } + + // x has typ &i32 + // for x in &v { + // println!("{x}"); + // } + + // x hsa type i32 + // for x in v { // this moves v + // println!("{x}"); + // } + + // println!("{v:?}"); // ERROR v is already moved + + let mut v = Vec::new(); + for i in 0..10 { + v.push(i); + } + + double(&mut v); + println!("{v:?}"); + + triple(&mut v); // you can pass vectors as slices also + println!("{v:?}"); + + triple(&mut v[1..4]); // can create sub slices + println!("{v:?}"); +} + +fn double(v: &mut Vec) { + for x in v { + *x *= 2 + } +} + +fn triple(s: &mut [i32]) { + for x in s { + *x *= 3 + } +}