rust Flashcards

1
Q

what type does the vector have to be to be able to call push on it

A

mutable

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

how can you make a copy of the variable n1?

A

let n4 = n1

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

what does this do?

let n2: &i32 = &n1;

A

a &i32 referring to n1

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

what does this do?

let n4 = n1;

A

// another i32 variable containing a copy of 1234

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

what will happen

let mut n1 = 1234_i64;
let n2 = &n1;
n1 = 4567;

A

compiles

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

what are three types of borrowing

A

use the original value;
have several immutable references to it;
have one mutable reference.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

what will happen:

let mut n1 = 1234;
let n2 = &mut n1;
*n2 = 4567;
println!(“{}”, *n2);
println!(“{} {}”, n1, n2);

A

let mut n1 = 1234;
let n2 = &mut n1; // note: a mutable reference
*n2 = 4567;
println!(“{}”, *n2);
//println!(“{} {}”, n1, n2); // “cannot borrow n1 as immutable because it is also borrowed as mutable”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

will this compile
let mut n1 = 1234;
{
let n2 = &mut n1;
*n2 = 4567;
println!(“{}”, *n2);
}
n1 = 7890;
println!(“{}”, n1);

A

let mut n1 = 1234;
{
let n2 = &mut n1;
*n2 = 4567;
println!(“{}”, *n2); // prints 4567
} // n2 is out of scope here, so no longer has a reference
n1 = 7890;
println!(“{}”, n1); // prints 7890

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

will this compile

let mut n1 = 1234;
let n2 = &mut n1;
let n3 = &mut n1;

A

yes

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

what happens when you pass a value to a function

A

When a value is passed to a function, ownership is given permanently to the function. Or, ownership moves to the function: is transferred permanently.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

will this compile

sum_vec(nums: Vec<i64>) -> Vec<64> {}</i64>

let numbers = Vec::from([1, 2, 3, 4]);
println!(“{}”, sum_vec(numbers));
println!(“”, numbers);

A

let numbers = Vec::from([1, 2, 3, 4]);
println!(“{}”, sum_vec(numbers)); // prints 10
println!(“”, numbers);

borrow of moved value: numbers

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

how do you ask for references

A

fn some_func( val : &Vec<i64>) -> i64 { ...}</i64>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

will this compile

fn sum_vec(values: &Vec<i64>) -> i64 {
values.iter().fold(0, |a, b| a + b)
}</i64>

let numbers = Vec::from([1, 2, 3, 4]);
println!(“{}”, sum_vec(&numbers));
println!(“”, numbers);

A

yes

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

question; what happens if i pass append_sum(mut val); ?

A

chatgpt it

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

will this compile:

let mut numbers = Vec::from([1, 2, 3, 4]);
append_sum(&mut numbers);
println!(“”, numbers);

A

let mut numbers = Vec::from([1, 2, 3, 4]);
append_sum(&mut numbers);
println!(“”, numbers); // prints [1, 2, 3, 4, 10]

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

what are the two ownership rules

A
  • At any given time, you can have either one mutable reference or any number of immutable references.
  • References must always be valid.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

whats the function argument type for a mutable reference

A

&mut

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

will this work:

fn sum_vec(values: Vec<i64>) -> i64 {
values.iter().fold(0, |a, b| a + b)
}</i64>

fn main() {
let numbers = Vec::from([1, 2, 3, 4]);
let summed = sum_vec(numbers);
println!(“{}”, summed);
println!(“{}”, summed);
}

A

yes

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

will this work:

fn sum_vec(values: Vec<i64>) -> i64 {
values.iter().fold(0, |a, b| a + b)
}</i64>

fn main() {
let numbers = Vec::from([1, 2, 3, 4]);
let summed = sum_vec(numbers);
println!(“”, numbers);

}

A

no, because its given to sum_vec

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

will this work:

fn sum_vec(values: &Vec<i64>) -> i64 {
values.iter().fold(0, |a, b| a + b)
}
fn main() {
let numbers = Vec::from([1, 2, 3, 4]);
let summed = sum_vec(numbers);
println!("{:?}", numbers);
println!("{}", summed);
}</i64>

A

no, becuase numbers is not passed as a reference in the main function

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

will this work:

fn sum_vec(values: &Vec<i64>) -> i64 {
values.iter().fold(0, |a, b| a + b)
}
fn main() {
let numbers = Vec::from([1, 2, 3, 4]);
let summed = sum_vec(&numbers);
println!("{:?}", numbers);
println!("{}", summed);</i64>

A

yes

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

will this work:

fn print_int(n: i64) {
println!(“”, n);
}
fn print_vec(v: Vec<i64>) {
println!("{:?}", v);
}</i64>

let n: i64 = 7;
let v: Vec<i64> = Vec::from([1, 2, 3, 4]);
println!("n: {:?}", n);
println!("v: {:?}", v);
print_int(n);
print_vec(v);
println!("n: {:?}", n);
println!("v: {:?}", v);</i64>

A

only works for print n because Vec does not implement Copy trait

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

what are some requirements to automatically copy a value as a reference to a function

A

types that implement the copy trait

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q

what are the types that have their ownership given away when they are assigned to a different variable?

A

non-copy types

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
Q

describe these lines of code:

let n1: i64 = 7;
let v1: Vec<i64> = Vec::from([1, 2, 3, 4]);
let n2 = n1;
let v2 = v1;
println!("n1: {:?}", n1);
println!("n2: {:?}", n2);
println!("v1: {:?}", v1);
println!("v2: {:?}", v2);</i64>

A

let n1: i64 = 7;
let v1: Vec<i64> = Vec::from([1, 2, 3, 4]);
let n2 = n1; // implicitly a copy, because i64 is Copy
let v2 = v1; // *implicitly a move*, because Vec is not Copy
println!("n1: {:?}", n1);
println!("n2: {:?}", n2);
//println!("v1: {:?}", v1); // "borrow of moved value: `v1`"
println!("v2: {:?}", v2);</i64>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
26
Q

how to implement copy

A

[derive(Copy, Clone)]

Summary:
- derive from Copy, Clone
- or, call clone on the fields

struct MyStruct;

  1. struct MyStruct {
    field1: String,
    field2: Vec<u64>,
    }</u64>

impl Clone for MyStruct {
fn clone(&self) -> Self {
MyStruct {
field1: self.field1.clone(),
field2: self.field2.clone(),
}
}
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
27
Q

why is it hard to implement copy trait for a vector?

A

The Vec keeps most of its data on the heap: copying its stack value would create multiple references to that heap memory.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
28
Q

which is implicit:

cloning or copying

A

copying is implicit but cloning is not

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
29
Q

what does #[derive(Debug, Clone)] do

A

The #[derive…] line gets us free implementations of Debug (printing with {:?}) and Clone (a .clone() method).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
30
Q

how to initialize a struct so that the struct is modifiable

A

let mut p = GeoPoint {…}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
31
Q

how to implement the following function in struct

fn antipode(&self) -> GeoPoint {}

A

impl GeoPoint {
fn antipode(&self) -> GeoPoint {
GeoPoint {
lat: -self.lat,
lon: -self.lon,
ele: self.ele,
}
}
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
32
Q

what is equivalent to this:

fn antipode(&self) -> GeoPoint {…}

A

fn antipode(self: &GeoPoint) -> GeoPoint {…}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
33
Q

what are the 3 receiving arguments for a struct. and what are they used for

A
  • the value itself (self): when the struct is no longer needed
  • or a reference (&self):
  • a mutable reference (&mut self): change a structs own content
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
34
Q

what is an associated function

A

If we implement a function on a type that does not have a receiver argument (self), it is an associated function (≈ static method).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
35
Q

how do you access associated functions

A

Associated functions are accessed from the type with ::

let p = GeoPoint::new(49.267, -122.967);

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
36
Q

how do you simplify this:

impl GeoPoint {
fn new(lat: f64, lon: f64) -> GeoPoint {
GeoPoint {
lat: lat,
lon: lon,
ele: 0,
}
}
}

A

fn new(lat: f64, lon: f64) -> GeoPoint {
GeoPoint { lat, lon, ele: 0 }
}

37
Q

how do you create a destructor

A

by creating a method with self ownership:

fn consume(self) {…}

38
Q

implement Display trait for GeoPoint, where the trait definition is:
pub trait Display {
// Required method
fn fmt(&self, f: &mut Formatter<’_>) -> Result<(), Error>;
}

and GeoPoint is:

impl GeoPoint {
fn new(lat: f64, lon: f64) -> GeoPoint {
GeoPoint {
lat: lat,
lon: lon,
ele: 0,
}
}
}

A

Reminders:
- write!(f, “{}, {}, {}”, self.lat, self.lon, self.ele)

use std::fmt;
impl fmt::Display for GeoPoint {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, “{}°N {}°E @ {}m”, self.lat, self.lon, self.ele)
}
}

39
Q

how to implement a default constructor

A
  1. # [derive(Default)]

2.
struct Foo {
x: i32,
y: String,
}

impl Foo {
fn new() -> Foo {
Foo {
x: 0,
y: String::from(“default”),
}
}
}

40
Q

define your own upable trait for geopoint

A

pub trait Upable {
fn move_up(&mut self, height: i32);
fn copy_up(&self, height: i32) -> Self;
}
impl Upable for GeoPoint {
fn move_up(&mut self, height: i32) {
self.ele += height;
}
fn copy_up(&self, height: i32) -> GeoPoint {
let mut dup = (*self).clone();
dup.move_up(height);
dup
}
}

41
Q

understand all this:

let v1: Vec<i64> = Vec::new();
let v2 = Vec::<i64>::new();
let v3 = returns_a_vec_i64();
let mut v4 = Vec::new();
v4.push(1234_i64);</i64></i64>

A

let v1: Vec<i64> = Vec::new(); // explicit type
let v2 = Vec::<i64>::new(); // type parameter in initializer
let v3 = returns_a_vec_i64(); // implied by initializer
let mut v4 = Vec::new(); // type-inferred in next line...
v4.push(1234_i64);</i64></i64>

42
Q

write your own pari_with_one function that returns a tuple containing a value of any time with a value 1

A

fn pair_with_one<T>(a: T) -> (T, i64) {
(a, 1)
}</T>

let pair1: (&str, i64) = pair_with_one(“hello”);
let pair2: (f64, i64) = pair_with_one(1.2345);

43
Q

write a generic type class that contains two generic type vectors and write an example on how to use it

A

[derive(Debug)]

Main thing to note:

  • impl<T> Default for tv<T> {</T></T>
  • fn default() -> tv<T> {</T>

struct TwoVecs<T> {
pub first: Vec<T>,
pub second: Vec<T>,
}
impl<T> Default for TwoVecs<T> {
fn default() -> TwoVecs<T> {
TwoVecs {
first: Vec::default(), // type-inferred as Vec<T>
second: Vec::default(),
}
}
}</T></T></T></T></T></T></T>

let mut tv = TwoVecs::<i32>::default();
let mut tv = TwoVecs::default();
tv.first.push(1234);
println!("{:?}", tv); // TwoVecs { first: [1234], second: [] }</i32>

`

44
Q

will this work:

fn is_larger<T>(a: T, b: T) -> bool {
a > b
}</T>

A

make it work:
- This function now takes two arguments (1) of the same type, (2) if that type implements Ord.

fn is_larger<T: Ord>(a: T, b: T) -> bool {
a > b
}

45
Q

Monomorphization

A

compiles a version of a function for every “dynamic” type that the function is used for

46
Q

will this work

fn is_larger<T: Ord>(a: T, b: T) -> bool {
a > b
}

A

yes

47
Q

Week 10.0

A
48
Q

implement IntoIterator for this struct

pub struct Container {
items: Vec<i32>,
}</i32>

impl Container {
pub fn new(items: Vec<i32>) -> Self {
Self { items }
}
}</i32>

TRAIT:

pub trait IntoIterator {
type Item;
type IntoIter: Iterator<Item = Self::Item>;

// Required method
fn into_iter(self) -> Self::IntoIter; }
A

impl IntoIterator for Container {
type Item = i32;
type IntoIter = std::vec::IntoIter<Self::Item>;

fn into_iter(self) -> Self::IntoIter {
    self.items.into_iter()
} }
49
Q

[derive(Debug, Clone)]

implement add for GeoPoint

struct GeoPoint {
pub lat: f64,
pub lon: f64,
pub ele: i32,
}

pub trait Add<Rhs = Self> {
type Output;

// Required method
fn add(self, rhs: Rhs) -> Self::Output; }
A

REMINDER:
- don’t forget to fill in Output
use std::ops::Add;
impl Add for GeoPoint {
type Output = GeoPoint;
fn add(self, other: GeoPoint) -> GeoPoint {
GeoPoint {
lat: self.lat + other.lat,
lon: self.lon + other.lon,
ele: self.ele + other.ele,
}
}
}

50
Q

if you create a struct, can you compare it to different types?

A

yes

51
Q

Implement PartialEq (==) for Geopoint:

A

impl PartialEq<GeoPoint> for GeoPoint {
fn eq(&self, other: &GeoPoint) -> bool {
self.lat == other.lat && self.lon == other.lon
}
}</GeoPoint>

52
Q

understand how to read this:

impl<T, U, A1, A2> PartialEq<Vec<U, A2» for Vec<T, A1>
where
A1: Allocator,
A2: Allocator,
T: PartialEq<u>,</u>

A

impl<T, U, A1, A2> … : This part introduces type parameters T, U, A1, and A2. T and U will be the types of the elements in the vectors. A1 and A2 are allocator types. In Rust, you can specify custom allocators for Vec, although the standard library provides a global allocator that is used by default.

PartialEq<Vec<U, A2» for Vec<T, A1> : This is saying “I’m going to define how to check for equality between a Vec<T, A1> and a Vec<U, A2>”. PartialEq is the trait for types which have a partial equivalence relation, which is basically a fancy way of saying that you can compare them for equality.

where A1: Allocator, A2: Allocator, T: PartialEq<u> : This part is a set of constraints on the type parameters. It says "this implementation applies when A1 and A2 are types that implement the Allocator trait, and when values of type T can be compared for equality with values of type U".</u>

let v1: Vec<i32> = vec![1, 2, 3];
let v2: Vec<f64> = vec![1.0, 2.0, 3.0];</f64></i32>

if v1 == v2 {
println!(“The vectors are equal.”);
}
In this case, T is i32, U is f64, and A1 and A2 are the default allocators. The equality check works because i32 implements PartialEq<f64>.</f64>

53
Q

what will this result in and understand why:

let v: Vec<i64> = Vec::from([1, 2, 3]);
let a: [i64; 3] = [1, 2, 3];
println!("{}", v == a);</i64>

A

let v: Vec<i64> = Vec::from([1, 2, 3]);
let a: [i64; 3] = [1, 2, 3];
println!("{}", v == a); // true</i64>

The comparison v == a prints true because Rust provides an implementation of the PartialEq trait for slices (and Vec<T> can deref to slices). This allows the comparison between a Vec<T> and an array.</T></T>

54
Q

whats the destructor in rust

A

.drop()

55
Q

write an example on how to user from and into using vec and array

  1. From: array of [1,2,3] to vector
  2. Into: array of [1,2,3] to vector
A

fn main() {
// Using From trait to convert an array into a Vec
let arr: [i32; 3] = [1, 2, 3];
let vec_from_array: Vec<i32> = Vec::from(arr);
println!("{:?}", vec_from_array); // prints: [1, 2, 3]</i32>

// Using Into trait to achieve the same thing
let vec_from_array_2: Vec<i32> = arr.into();
println!("{:?}", vec_from_array_2);  // prints: [1, 2, 3] }
56
Q

answer the following quesitons for the Option Type:

  • what is it used for
  • what are the types
  • what are the important methods that you can call on
A
  • Used to represent a value that might be missing. Doesn’t feel like an error value, just a value that might be missing
  • It can be either: Some(t), None
  • Can use the following to check its state
    is_some()
    is_none()
57
Q

implement find_elt and write a match case for this to print out weather it has been found or not:

let v1: Vec<i32> = Vec::from([4, 5, 2, 8, 7, 3, 1]);
let pos: Option<usize> = find_elt(&v1, 8);</usize></i32>

A

fn find_elt<T: PartialEq>(vec: &Vec<T>, element: T) -> Option<&T> {
for ele in vec.iter() {
if *ele == element {
return Some(ele);
}
}
None
}</T>

fn main() {
let v = vec![1, 2, 3, 4];

match find_elt(&v, 3) {
    Some(ele) => {
        println!("Found: {}", ele);
    }
    None => {
        println!("Element not found");
    }
} }
58
Q

what are the properties for Result<T, E>? what are the important methods?

A

Don’t expect fail
Gives:
Ok(T)
Err(E)

useful methods:
.is_ok()

59
Q

differences between Result and Option

A

Option is for null value, Result can be fore exeption

60
Q

give this
let response: reqwest::blocking::Response;

match it so that if Err, prints err and exists
Ok, print ok

A

match res {
Err(e) => {
println!(“Request failed: {}”, e);
return;
}
Ok(r) => {
response = r;
}
}
let status = response.status();
println!(“Status code {}.”, status);

61
Q

what are the properties of ? Operator

A
  • Pass the error up to the parent
  • Unchecked exception
  • The ? operator can be used on any Result. The semantics: if Err, return the Err immediately; else .unwrap() and continue
62
Q

given:
use reqwest::blocking::get;
use reqwest::Error as ReqwestError;
pub fn get<T: IntoUrl>(url: T) -> Result<Response></Response>

write a function that uses get and returns a Result object so that who ever calls this function has to deal with the error response.

should return response.text()

A

use reqwest::blocking::get;
use reqwest::Error as ReqwestError;
fn url_fetch(url: String) -> Result<String, ReqwestError> {
let response = get(url)?;
let text = response.text()?;
Ok(text)
}

Or

fn url_fetch_2(url: String) -> Result<String, ReqwestError> {
Ok(get(url)?.text()?)
}

63
Q

how to avoid panicing when unwrapping

A

make sure that the Result object is Ok before unwrapping

64
Q

Result vs Option

A
65
Q

write a thread that returns a “hello word” string. take the thread output and print it

A

let h2 = thread::spawn(|| String::from(“Hello”) + “ world”);
println!(“h1 result: {:?}”, h1.join().unwrap());

66
Q

understand closures with threads in rust

A

search it up

67
Q

will this work, why or why not:

let data = Vec::from([1, 2, 3, 4, 5, 6, 7]);
let h = thread::spawn(|| {
println!(“The third element is {}”, data[3]);
});
h.join().unwrap();

A

closure may outlive the current function, but it borrows
data, which is owned by the current function

68
Q

what would happen here:

let data = Vec::from([0, 1, 2, 3, 4, 5, 6, 7]);
let h = thread::spawn(move || {
println!(“The third element is {}”, data[3]);
});
println!(“{}”, data[0]);
h.join().unwrap();

A

let data = Vec::from([0, 1, 2, 3, 4, 5, 6, 7]);
let h = thread::spawn(move || {
println!(“The third element is {}”, data[3]);
});
println!(“{}”, data[0]); // compile error here
h.join().unwrap();

69
Q

make this work:

let data = Vec::from([0, 1, 2, 3, 4, 5, 6, 7]);
let h = thread::spawn(move || {
println!(“The third element is {}”, data[3]);
});
println!(“{}”, data[0]);
h.join().unwrap();

A

let data = Vec::from([0, 1, 2, 3, 4, 5, 6, 7]);
let data_clone = data.clone(); // Create a clone of the data
let h = thread::spawn(move || {
println!(“The third element is {}”, data_clone[3]); // Use the clone in the spawned thread
});
println!(“{}”, data[0]); // Now you can use data in the main thread as well
h.join().unwrap();

70
Q

Implement a concurrent program using Rust’s mpsc (multi-producer, single consumer) channel, where three spawned threads each send their index multiplied by 10 to the main thread via the channel. Ensure the main thread receives and prints these values.

A

reminders:
- initialize using channel();
- receive th value using .recv().unwrap();

use std::sync::mpsc;
let (sender, receiver) = mpsc::channel();
for i in 0..3 {
let snd = sender.clone();
thread::spawn(move || {
snd.send(i * 10).unwrap();
});
}
for i in 0..3 {
println!(“”, receiver.recv());
}

71
Q

what does the Send trait do

A

The trait marks a value that Rust can
transfer ownership to another thread. Most
types are Send.

72
Q

what is the Sync trait

A

You have to know that they are imutable

  • a trait that indicates a type where it’s safe
    to share references between multiple threads.
  • Note: they must be immutable
73
Q

what are the three rules for memory management

A

Ownership - every value is owned by exactly one variable
Safe borrowing with references:
Either multiple immutable borrows
Unique mutable borrow
References cannot outlive their values

74
Q

zero-cost abstraction meaning

A

Reminder:
- know that option costs us run time performance

Almost none of these safety assurancecs cost us run-time performance.

except for Option

75
Q

whats the word for a version of this function is compiled for each T that you use it with.

A

monomorphization

76
Q

will this compile:

struct Node<T> {
value: T,
left: Option<Node<T>>,
right: Option<Node<T>>,
}</T></T></T>

A

no, the size of a type must be known at compile time. In this case, the size of Node<T> cannot be determined because it recursively includes itself in its own definition.</T>

77
Q

write a struct for a binary tree Node<T></T>

A

struct Node<T> {
value: T,
left: Option<Box<Node<T>>>,
right: Option<Box<Node<T>>>,
}</T></T></T>

78
Q

why doesnt this work:

struct Node<T> {
pub val: T;
pub left: Node<T>;
pub right: Node<T>;
}</T></T></T>

A
  • The reason is that Rust’s memory safety rules do not allow data structures with circular references without some form of indirection
  • the code as written does not specify lifetimes for the references, which would be needed for the code to compile. Lifetimes in Rust are a way of ensuring that references are valid for the duration they’re being used.

Here’s an example of how you might modify your code to use lifetimes and still compile:

struct Node<’a, T: ‘a> {
value: T,
left: Option<&’a Node<’a, T»,
right: Option<&’a Node<’a, T»,
}
However, this would still not allow for creating circular structures or self-referential structures because of Rust’s ownership rules.

79
Q

what are lifetime references

A

Lifetimes in Rust are used to prevent dangling references. That is, Rust uses lifetimes to ensure that all references are always valid. Rust does this by checking that the lifetime of any reference does not exceed the lifetime of the object it references.

80
Q

what does Box<T> do</T>

A
  • A Box can hold another value, takes ownership of that value, and makes sure the value lives as long as the Box exists
  • When a Box gets dropped, its contents will be
    dropped as well (because it owns the
    contents).
  • is not a copy but is a clone. clone -> clones the entire content of the box
  • auto dereferenced when printing boxes, or explicitly: let f2: f64 = *b2;
  • instantiate by: let f1 = 1.234; .rs
    let b1 = Box::new(f1);
  • The Box does implement AsMut and whenever
    we did mutable things inside a Box, there was
    an implicit dereference using .as_mut().
81
Q

implement the following methods for Node:
- new
- set_left
- set_right

struct Node<T> {
value: T,
left: Option<Node<T>>,
right: Option<Node<T>>,
}`</T></T></T>

A

Reminders:
- Box::new(…)
- Some(Box::new(Node::new(value)));

impl<T> Node<T> { .rs
fn new(value: T) -> Node<T> {
Node {
value,
left: None,
right: None,
}
}
fn set_left(&mut self, value: T) {
self.left =
Some(Box::new(Node::new(value)));
}
fn set_right(&mut self, value: T) {
self.right =
Some(Box::new(Node::new(value)));
}
}</T></T></T>

let mut n = Node::new(10); .rs
n.set_left(5);
n.set_right(15);
println!(“”, n);

82
Q

what should you use for multiple immutable references? and what can you do with it?

A

Rc<T></T>

Rc can be safely cloned and is guaranteed
to live as long as the contents are accessible.
It owns its contents, and drops them when
zero references remain.

use std::rc::Rc; .rs
let mut v = Vec::from([1, 2]);
v.push(3); // can get “&mut v” here
let r1 = Rc::new(v);
let r2 = r1.clone();

83
Q
  1. what does .iter() do?
  2. map the values in vec to times it by 2 and generate a new vec of it.
A

Reminder:
- the map must take in a &reference

What it does: Creates an immutable iterator over the collection.

let v = vec![1, 2, 3];
for i in v.iter() {
println!(“{}”, i);
}

FUNCTIONAL
let v = vec![1, 2, 3];
let doubled: Vec<_> = v.iter().map(|&x| x * 2).collect();
println!("{:?}", doubled); // [2, 4, 6]</_>

84
Q

understand .fold()

fn fold<B, F>(self, init: B, f: F) -> B
where
Self: Sized,
F: FnMut(B, Self::Item) -> B,

A

let v = vec![1, 2, 3, 4];
let product = v.iter().fold(1, |acc, &x| acc * x);
println!(“Product: {}”, product); // 24

85
Q

what is Arc

A

same as Rc but thread safe

86
Q

what kind of pointer should you use if you want multiple references to an object on the heap

A

mutex, Arc, Rc

87
Q

Type Sharable? Mutable? Thread Safe?
&
&mut
Box
Rc
Arc
RefCell
Mutex

A

Type Sharable? Mutable?Thread Safe?
& yes * no no
&mut no * yes no
Box no yes no
Rc yes no no
Arc yes no yes
RefCell yes ** yes no
Mutex yes, in Arc yes yes

  • but doesn’t own contents, so lifetime
    restrictions.
    ** while there is no mutable borrow
88
Q

how would you create a shared mutable state data structure?
give it to multiple threads that adds some value to it.

know how to destroy it

what would be the type of it?

A

Key things to remember:
- let mut val = values.lock().unwrap(); // MUST BE MUT

Algorithm:
- let value = Vec::new();
- let sharable_v = Arc::new(Mutex::new(value));
- clone shareble_v and pass it to thread
- store the handle and wait for all threads to finish by calling .join().unwrap() on them
- print it.

CREATE MUTABLE STATE STRUCTURE
let values = Vec::new();
let values_shared =
Arc::new(Mutex::new(values));
let mut handles = Vec::new();

PASS THEM TO THREADS
for i in 1..6 { .rs
let my_values_shared =
values_shared.clone();
let h = thread::spawn(move || {
add_some_values(my_values_shared, i);
});
handles.push(h);
}

ADD VALUE
fn add_some_values(values: .rs
Arc<Mutex<Vec<i64>>>, thread_id: i64) {
let mut rng = rand::thread_rng();
for _ in 0..3 {
let v = rng.gen_range(0..100);
{
let mut vals =
values.lock().unwrap();
vals.push(v + thread_id * 1000);
}
let delay = rng.gen_range(100..200);</i64>

thread::sleep(Duration::from_millis(delay));
}

DESTROY
let mutex =
Arc::into_inner(values_shared).unwrap();
let final_values = mutex.into_inner().unwrap();
println!(“”, final_values)

MUTEX TYPE
Arc<Mutex<Vec<i64>>></i64>

89
Q

Write the following out:
1. create a trait Can speak
2. create a struct speaker, and implement CanSpeak for it that prints “hello”
3. create a function called “speak_twice” that takes any object that implements the CanSpeak object dynamically, that calles the function .speak() twice
4. run the program to call speak_twice on the box

A

trait CanSpeak {
fn speak(&self) -> ();
}
struct Speaker {}
impl CanSpeak for Speaker {
fn speak(&self) -> () {
println!(“hello”);
}
}

fn speak_twice(s: &Box<dyn>) { .rs
s.speak();
s.speak();
}</dyn>

let s: Box<dyn> = Box::new(Speaker .rs
{});
s.speak();
speak_twice(&s);</dyn>