rust Flashcards

(89 cards)

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
describe these lines of code: let n1: i64 = 7; let v1: Vec = Vec::from([1, 2, 3, 4]); let n2 = n1; let v2 = v1; println!("n1: {:?}", n1); println!("n2: {:?}", n2); println!("v1: {:?}", v1); println!("v2: {:?}", v2);
let n1: i64 = 7; let v1: Vec = 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);
26
how to implement copy
Summary: - derive from Copy, Clone - or, call clone on the fields 1. #[derive(Copy, Clone)] struct MyStruct; 2. struct MyStruct { field1: String, field2: Vec, } impl Clone for MyStruct { fn clone(&self) -> Self { MyStruct { field1: self.field1.clone(), field2: self.field2.clone(), } } }
27
why is it hard to implement copy trait for a vector?
The Vec keeps most of its data on the heap: copying its stack value would create multiple references to that heap memory.
28
which is implicit: cloning or copying
copying is implicit but cloning is not
29
what does #[derive(Debug, Clone)] do
The #[derive…] line gets us free implementations of Debug (printing with {:?}) and Clone (a .clone() method).
30
how to initialize a struct so that the struct is modifiable
let mut p = GeoPoint {...}
31
how to implement the following function in struct fn antipode(&self) -> GeoPoint {}
impl GeoPoint { fn antipode(&self) -> GeoPoint { GeoPoint { lat: -self.lat, lon: -self.lon, ele: self.ele, } } }
32
what is equivalent to this: fn antipode(&self) -> GeoPoint {…}
fn antipode(self: &GeoPoint) -> GeoPoint {…}
33
what are the 3 receiving arguments for a struct. and what are they used for
- 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
34
what is an associated function
If we implement a function on a type that does not have a receiver argument (self), it is an associated function (≈ static method).
35
how do you access associated functions
Associated functions are accessed from the type with :: let p = GeoPoint::new(49.267, -122.967);
36
how do you simplify this: impl GeoPoint { fn new(lat: f64, lon: f64) -> GeoPoint { GeoPoint { lat: lat, lon: lon, ele: 0, } } }
fn new(lat: f64, lon: f64) -> GeoPoint { GeoPoint { lat, lon, ele: 0 } }
37
how do you create a destructor
by creating a method with self ownership: fn consume(self) {...}
38
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, } } }
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
how to implement a default constructor
1. #[derive(Default)] 2. struct Foo { x: i32, y: String, } impl Foo { fn new() -> Foo { Foo { x: 0, y: String::from("default"), } } }
40
define your own upable trait for geopoint
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
understand all this: let v1: Vec = Vec::new(); let v2 = Vec::::new(); let v3 = returns_a_vec_i64(); let mut v4 = Vec::new(); v4.push(1234_i64);
let v1: Vec = Vec::new(); // explicit type let v2 = Vec::::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);
42
write your own pari_with_one function that returns a tuple containing a value of any time with a value 1
fn pair_with_one(a: T) -> (T, i64) { (a, 1) } let pair1: (&str, i64) = pair_with_one("hello"); let pair2: (f64, i64) = pair_with_one(1.2345);
43
write a generic type class that contains two generic type vectors and write an example on how to use it
Main thing to note: - impl Default for tv { - fn default() -> tv { #[derive(Debug)] struct TwoVecs { pub first: Vec, pub second: Vec, } impl Default for TwoVecs { fn default() -> TwoVecs { TwoVecs { first: Vec::default(), // type-inferred as Vec second: Vec::default(), } } } let mut tv = TwoVecs::::default(); let mut tv = TwoVecs::default(); tv.first.push(1234); println!("{:?}", tv); // TwoVecs { first: [1234], second: [] } `
44
will this work: fn is_larger(a: T, b: T) -> bool { a > b }
make it work: - This function now takes two arguments (1) of the same type, (2) if that type implements Ord. fn is_larger(a: T, b: T) -> bool { a > b }
45
Monomorphization
compiles a version of a function for every "dynamic" type that the function is used for
46
will this work fn is_larger(a: T, b: T) -> bool { a > b }
yes
47
Week 10.0
48
implement IntoIterator for this struct pub struct Container { items: Vec, } impl Container { pub fn new(items: Vec) -> Self { Self { items } } } TRAIT: pub trait IntoIterator { type Item; type IntoIter: Iterator; // Required method fn into_iter(self) -> Self::IntoIter; }
impl IntoIterator for Container { type Item = i32; type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { self.items.into_iter() } }
49
implement add for GeoPoint #[derive(Debug, Clone)] struct GeoPoint { pub lat: f64, pub lon: f64, pub ele: i32, } pub trait Add { type Output; // Required method fn add(self, rhs: Rhs) -> Self::Output; }
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
if you create a struct, can you compare it to different types?
yes
51
Implement PartialEq (==) for Geopoint:
impl PartialEq for GeoPoint { fn eq(&self, other: &GeoPoint) -> bool { self.lat == other.lat && self.lon == other.lon } }
52
understand how to read this: impl PartialEq> for Vec where A1: Allocator, A2: Allocator, T: PartialEq,
impl ... : 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> for Vec : This is saying "I'm going to define how to check for equality between a Vec and a Vec". 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 : 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". let v1: Vec = vec![1, 2, 3]; let v2: Vec = vec![1.0, 2.0, 3.0]; 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.
53
what will this result in and understand why: let v: Vec = Vec::from([1, 2, 3]); let a: [i64; 3] = [1, 2, 3]; println!("{}", v == a);
let v: Vec = Vec::from([1, 2, 3]); let a: [i64; 3] = [1, 2, 3]; println!("{}", v == a); // true The comparison v == a prints true because Rust provides an implementation of the PartialEq trait for slices (and Vec can deref to slices). This allows the comparison between a Vec and an array.
54
whats the destructor in rust
.drop()
55
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
fn main() { // Using From trait to convert an array into a Vec let arr: [i32; 3] = [1, 2, 3]; let vec_from_array: Vec = Vec::from(arr); println!("{:?}", vec_from_array); // prints: [1, 2, 3] // Using Into trait to achieve the same thing let vec_from_array_2: Vec = arr.into(); println!("{:?}", vec_from_array_2); // prints: [1, 2, 3] }
56
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
- 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
implement find_elt and write a match case for this to print out weather it has been found or not: let v1: Vec = Vec::from([4, 5, 2, 8, 7, 3, 1]); let pos: Option = find_elt(&v1, 8);
fn find_elt(vec: &Vec, element: T) -> Option<&T> { for ele in vec.iter() { if *ele == element { return Some(ele); } } None } 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
what are the properties for Result? what are the important methods?
Don’t expect fail Gives: Ok(T) Err(E) useful methods: .is_ok()
59
differences between Result and Option
Option is for null value, Result can be fore exeption
60
give this let response: reqwest::blocking::Response; match it so that if Err, prints err and exists Ok, print ok
match res { Err(e) => { println!("Request failed: {}", e); return; } Ok(r) => { response = r; } } let status = response.status(); println!("Status code {}.", status);
61
what are the properties of ? Operator
- 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
given: use reqwest::blocking::get; use reqwest::Error as ReqwestError; pub fn get(url: T) -> Result 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()
use reqwest::blocking::get; use reqwest::Error as ReqwestError; fn url_fetch(url: String) -> Result { let response = get(url)?; let text = response.text()?; Ok(text) } Or fn url_fetch_2(url: String) -> Result { Ok(get(url)?.text()?) }
63
how to avoid panicing when unwrapping
make sure that the Result object is Ok before unwrapping
64
Result vs Option
65
write a thread that returns a "hello word" string. take the thread output and print it
let h2 = thread::spawn(|| String::from("Hello") + " world"); println!("h1 result: {:?}", h1.join().unwrap());
66
understand closures with threads in rust
search it up
67
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();
closure may outlive the current function, but it borrows `data`, which is owned by the current function
68
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();
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
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();
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
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.
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
what does the Send trait do
The trait marks a value that Rust can transfer ownership to another thread. Most types are Send.
72
what is the Sync trait
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
what are the three rules for memory management
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
zero-cost abstraction meaning
Reminder: - know that option costs us run time performance Almost none of these safety assurancecs cost us run-time performance. except for Option
75
whats the word for a version of this function is compiled for each T that you use it with.
monomorphization
76
will this compile: struct Node { value: T, left: Option>, right: Option>, }
no, the size of a type must be known at compile time. In this case, the size of Node cannot be determined because it recursively includes itself in its own definition.
77
write a struct for a binary tree Node
struct Node { value: T, left: Option>>, right: Option>>, }
78
why doesnt this work: struct Node { pub val: T; pub left: Node; pub right: Node; }
- 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
what are lifetime references
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
what does Box do
- 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
implement the following methods for Node: - new - set_left - set_right struct Node { value: T, left: Option>, right: Option>, }`
Reminders: - Box::new(...) - Some(Box::new(Node::new(value))); impl Node { .rs fn new(value: T) -> Node { 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))); } } let mut n = Node::new(10); .rs n.set_left(5); n.set_right(15); println!("{:?}", n);
82
what should you use for multiple immutable references? and what can you do with it?
Rc 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
1. what does .iter() do? 2. map the values in vec to times it by 2 and generate a new vec of it.
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
understand .fold() fn fold(self, init: B, f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B,
let v = vec![1, 2, 3, 4]; let product = v.iter().fold(1, |acc, &x| acc * x); println!("Product: {}", product); // 24
85
what is Arc
same as Rc but thread safe
86
what kind of pointer should you use if you want multiple references to an object on the heap
mutex, Arc, Rc
87
Type Sharable? Mutable? Thread Safe? & &mut Box Rc Arc RefCell Mutex
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
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?
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>>, 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); 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>>
89
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
trait CanSpeak { fn speak(&self) -> (); } struct Speaker {} impl CanSpeak for Speaker { fn speak(&self) -> () { println!("hello"); } } fn speak_twice(s: &Box) { .rs s.speak(); s.speak(); } let s: Box = Box::new(Speaker .rs {}); s.speak(); speak_twice(&s);