rust

created : Sun, 12 Feb 2023 16:52:36 +0900
modified : Thu, 23 Mar 2023 20:33:27 +0900
rust

공부 자료

혼자 정리

Hello World!

Small Example

Why Rust?

Compile Time Guarantees

Runtime Guarantees

References

Dangling References

Slices

String vs str

Functions

fn main() {
  fizzbuzz_to(20);
}

fn is_divisible_by(lhs: u32, rhs: u32) -> bool {
  if rhs == 0 {
    return false;
  }
  lhs % rhs == 0
}

fn fizzbuzz(n: u32) -> () {
  match (is_divisible_by(n, 3), is_divisible_by(n, 5)) {
    (true, true) => println!("fizzbuzz"),
    (true, false) => println!("fizz"),
    (false, true) => println!("buzz"),
    (false, false) => println!("{n}"),
  }
}

fn fizzbuzz_to(n: u32) {
  for i in 1..=n {
    fizzbuzz(i);
  }
}

Mtehods

struct Rectangel {
  width: u32,
  height: u32,
}

impl Rectangle {
  fn area(&self) -> u32 {
    self.width * self.height
  }

  fn inc_width(&mut self, delta: u32) {
    self.width += delta;
  }
}

fn main() {
  let mut rect = Rectangle { width: 10, height: 5 };
  println!("old area: {}", rect.area());
  rect.inc_widtH(5);
  println!("new area: {}", rect.area());
}

Function Overloading

Static and Constant Variables

Scopes and Shadowing

Memory Management

The Stack vs The Heap

Memory Management in Rust

Comparison

Pros of Different Memory Management Techniques

Cons of Different Memory Mangement Techniques

Ownership

Move Semantics

Moves in Function Calls

Copying and Cloning

Borrowing

Shared and Unique Borrows

fn main() {
  let mut a: i32 = 10;
  let b: &i32 = &a;

  {
    let c: &mut i32 = &mut a;
    *c = 20;
  }

  println!("a: {a}");
  println!("b: {b}");
}

Lifetimes

Structs

struct Person {
  name: String,
  age: u8,
}

fn main() {
  let mut peter = Person {
    name: String::from("Peter"),
    age: 27,
  };
  println!("{} is {} years old", peter.name, peter.age);

  peter.age = 28;
  println!("{} is {} years old", peter.name, peter.age);

  let jackie = Person {
    name: String::from("Jackie"),
    ..peter
  };

  println!("{} is {} years old", jackie.name, jackie.age);
}

Tuple Structs

struct Point(i32, i32);

struct Newtons(f64);

Field Shorthand Syntax

struct Person {
  name: String,
  age: u8,
}

impl Person {
  fn new(name: String, age: u8) -> Person {
    Person { name, age }
  }
  /*
  fn new(name: String, age: u8) -> Self {
    Self { name, age }
  }
  */
}

fn main() {
  let peter = Person::new(String::from("Peter"), 27);
  println!("{peter:?}");
}

Enums

fn generate_random_number() -> i32 {
  4
}

enum CoinFilp {
  Heads,
  Tails,
}

fn flip_coin() -> CoinFlip {
  let random_number = generate_random_number();
  if random_number % 2 == 0 {
    return CoinFlip::Heads;
  } else {
    return CoinFlip::Tails;
  }
}

fn main() {
  println!("You got: {:?}", flip_coin());
}

Variant Payloads

enum WebEvent {
  PageLoad,
  KeyPress(char),
  Click { x: i64, y: i64 },
}

fn inspect(event:WebEvnet) {
  match event {
    WebEvent::PageLoad => println!("page loaded"),
    WebEvent::KeyPress(c) => println!("pressed '{c}'"),
    WebEvent::Click { x, y } => println!("clicked at x={x}, y={y}"),
  }
}

fn main() {
  let load = WebEvent::PageLoad;
  let press = WebEvent::KeyPress('x');
  let click = WebEvent::Click { x: 20, y: 80 };

  inspect(load);
  inspect(press);
  inspect(click);
}

Methods

struct Person {
  name: String,
  age: u8,
}

impl Person {
  fn say_hello(&self) {
    println!("Hello, my name is {}", self.name);
  }
}

fn main() {
  let peter = Person {
    name: String::from("Peter"),
    age: 27,
  };
  peter.say_hello();
}

Method Receiver

Pattern Matching

fn main() {
  let input = 'x';

  match input {
    'q' => println!("Quitting"),
    'a' | 's' | 'w' | 'd' => println!("Moving around"),
    '0'..='9' => println!("Number input"),
    _ => println!("Something else"),
  }
}

Destructing Structs

struct Foo {
  x: (u32, u32),
  y: u32,
}

fn main() {
  let foo = Foo { x: (1, 2), y: 3};
  match foo {
    Foo { x: (1, b), y } => println!("x.0 = 1, b = {b}, y = {y}"),
    Foo { y: 2, x: i } => println!("y = 2, x = {i:?}"),
    Foo { y, .. } => println!("y = {y}, other fields were ignored"),
  }
}

Match Guards

fn main() {
    let pair = (2, -2);
    println!("Tell me about {pair:?}");
    match pair {
        (x, y) if x == y     => println!("These are twins"),
        (x, y) if x + y == 0 => println!("Antimatter, kaboom!"),
        (x, _) if x % 2 == 1 => println!("The first one is odd"),
        _                    => println!("No correlation..."),
    }
}

Control Flow

Block

fn main() {
  let x = {
    let y = 10;
    println!("y: {y}");
    let z = {
      let w = {
        3 + 4
      };
      println!("w: {w}");
      y * w
    };
    println!("z: {z}");
    z - y
  };
  println!("x: {x}");
}

if expressions

if let expressions

fn main() {
  let arg = std::env::args().next();
  if let Some(value) = arg {
    println!("Program name: {value}");
  } else {
    println!("Missing name?");
  }
}

while expressions

for expressions

fn main() {
  let v = vec![10, 20, 30];

  for x in v {
    println!("x: {x}");
  }

  for i in (0..10).step_by(2) {
    println!("i: {i}");
  }
}

loop expresssions

fn main() {
  let mut x = 10;
  loop {
    x = if x % 2 == 0 {
      x / 2
    } else {
      3 * x + 1
    };
    if x == 1 {
      break;
    }
  }
  println!("Final x: {x}");
}

match expressions

break and continue

fn main() {
  let v = vec![10, 20, 30];
  let mut iter = v.into_iter();
  'outer: while let Some(x) = iter.next() {
    println!("x: {x}");
    let mut i = 0;
    while i < x {
      println!("x: {x}, i: {i}");
      i += 1
      if i == 3 {
        break 'outer;
      }
    }
  }
}

Standard Library

Option and Result

String

fn main() {
  let mut s1 = String::new();
  s1.push_str("Hello");
  println!("s1: len = {}, capacity = {}", s1.len(), s1.capacity());

  let mut s2 = String::with_capacity(s1.len() + 1);
  s2.push_str(&s1);
  s2.push("!");
  println!("s2: len = {}, capcity = {}", s2.len(), s2.capacity());

  let s3 = String::from("🇨🇭");
  println!("s3: len = {}, number of chars = {}", s3.len(), s3.chars().count());
}

Vec

HashMap

Box

Niche Optimization

#[drive(Debug)]
enum List<T> {
  Cons(T, Blox<List<T>>),
  Nil,
}

fun main() {
  let list: List<i32> = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));
  println!("{list:?}");
}

Rc

Modules

mod foo {
  pub fn do_something() {
    println!("In the foo module");
  }
}

mod bar {
  pub fn do_something() {
    println!("In the bar module");
  }
}

fn main() {
  foo::do_something();
  bar::do_something();
}

Visibility

Paths

Filesystem Hierarchy

Traits

trait Greet {
  fn say_hello(&self);
}

struct Dog {
  name: String,
}

struct Cat;

impl Greet for Dog {
  fn say_hello(&self) {
    println!("Wuf, my name is {}!", self.name);
  }
}

impl Greet for Cat {
  fn say_hello(&self) {
    println!("Miau!");
  }
}

fn main() {
  let pets: Vec<Box<dyn Greet>> = vec![
    Box::new(Dog { name: String::from9"Fido") }),
    Box::new(Cat),
  ];
  for pet in pets {
    pet.say_hello();
  }
}

Important Traits

Iterator

FromIterator

From and Into

fn main() {
  let s = String::from("hello");
  let addr = std::net::Ipv4Addr::from([127, 0, 0, 1]);
  let one = i16::from(true);
  let bigger = i32::form(123i16);
  println!("{s}, {addr}, {one}, {bigger}");
}

fn main() {
  let s: String = "hello".into();
  let addr: std::net::Ipv4Addr = [127, 0, 0, 1].into();
  let one: i16 = true.into();
  let bigger: i32 = 123i16.into();
  println!("{s}, {addr}, {one}, {bigger}");
}

Read and Write

Add, Mul, …

The Drop Trait

The Default Trait

Generics

Generic Data Types

#[derive(Debug)]
struct Point<T> {
  x: T,
  y: T,
}

fn main() {
  let integer = Point { x: 5, y: 10 };
  let float = Point { x: 1.0, y: 4.0 };
  println!("{integer:?} and {float:?}");
}

Generic Method

Trait Bounds

fn duplicate<T: Clone>(a: T) -> (T, T) {
  (a.clone(), a.clone())
}

fn add_42_millions(x: impl Into<i32>) -> i32 {
  x.into() + 42_000_000
}

fn main() {
  let foo = String::from("foo");
  let pair = duplicate(foo);
  println!("{pair:?}");

  let many = add_42_millions(42_i8);
  println!("{many}");
  let many_more = add_42_millions(10_000_000):
  println!("{many_mor}");
}

closures

Error Handling

Panics

Structured Error Handling with Result

use std::fs::File;
use std::io::Read;

fn main() {
  let file = File::open("diary.txt");
  match file {
    Ok(mut file) => {
      let mut contents = String::new();
      file.read_to_string(&mut contents);
      println!("Dear diary: {contents}");
    },
    Err(err) => {
      println!("The diary could not be opened: {err}");
    }
  }
}

Propagating Erros with?

use std::(fs, io);
use std::io::Read;
use thiserror::Error;

#[derive(Debug, Error)]
enum ReadUsernameError {
  #[error("Could not read: {0}")]
  IoError(#[from] io::Error),
  #[error("Found no username in {0}")]
  EmptyUsername(String),
}

fn read_username(path: &str) -> Result<String, ReadUsernameError> {
  let mut username = String::with_capacity(100);
  fs:File::oepn(path)?.read_to_string(&mut unsername)?;
  if username.is_empty() {
    return Err(ReadUsernameError::EmptyUsername(String::from(path)));
  }
  Ok(username)
}

fn main() {
  //fs::write("config.dat", "").unwrap();
  match read_uername("config.dat") {
    Ok(username) => println!("Username: {username}"),
    Err(err)     => println!(Error: {err}),
  }
}

Testing

fn first_word(text: &str) -> &str {
  match text.find(' ') {
    Some(idx) => &text[..idx],
    None => &text,
  }
}

#[test]
fn test_empty() {
  assert_eq!(first_word(""), "");
}

#[test]
fn test_single_word() {
  assert_eq!(first_wrod("Hello"), "Hello");
}

#[test]
fn test_multiple_words() {
  assert_eq!(first_word("Hello World"), "Hello");
}

Unsafe Rust

Unions

union MyUnion {
  i: u8,
  b: bool,
}

fn main() {
  let u = MyUnion { i: 42 };
  println!("int: {}", unsafe { u.i });
  println!("bool: {}", unsafe { u.b });
}

Calling External Code

extern "C" {
  fn abs(input: i32) -> i32;
}
fn main() {
  unsafe {
    println!("Absolute value of -3 according to C: {}", abs(-3));
  }
}

Concurrency

Threads

use std::thread;
use std::time::Duration;

fn main() {
  let handle = thread::spawn(|| {
    for i in 1..10 {
      println!("Count in thread: {i}!");
      thread::sleep(Duration::from_millis(5));
    }
  });

  for i in 1..5 {
    println!("Main thread: {i}");
    thread::sleep(Duration::from_millis(5));
  }
  handle.join();
}

Scoped Threads

use std::thread;

fn main() {
  let s = String::from("Hello");

  thread::scope(|scope| {
    scope.spawn(|| {
      println!("Length: {}", s.len());
    })
  });
}

Channels

use std::sync::mpsc;
use std::thread;

fn main() {
  let (tx, rx) = mpsc::channel();

  tx.send(10).unwrap();
  tx.send(20).unwrap();

  println!("Received: {:?}", rx.recv());
  println!("Recieved: {:?}", rx.recv());

  let tx2 = tx.clone();
  tx2.send(30).unwrap();
  println!("Received: {:?}", rx.recv());
}

Shared State