Griffin SC HW 07 - TheEvergreenStateCollege/upper-division-cs-23-24 GitHub Wiki
Reading
Chapter 10 - Generic Types, Traits and Lifetimes
generics an abstract stand in for concrete types or other properties Q. What is a concrete type? A.
"Generics allow us to replace specific types with a placeholder that represents multiple types to remove code duplication."
generic type T as parameter, and notice syntax after function name. Also returns generic type T:
You can implement functions for specific types:
important to note:
performance
generics don't affect run time performance because Rust uses monomorphization which turns generic code into concrete code during compile time. Would this affect compile time?
10.1. Generic Data Types
I can't explain this one. It's a logical problem, where the only possible function is the identify function.
so basically, Rust doesn't assume anything about the types so the only operation it can do is return whatever value is passed to it
we pass the address a slice, from an array of integers. And then try to convert the integers to a string, but because it is generic we don't know it is an integer, and therefore aren't able to convert to a string. In other words we cannot assume that the passed integer slice has the ToString trait, which allows us to convert from int to string. so i.e. when working with generic types we need to specify the type otherwise Rust won't be able to access the type traits
rust doesn't know which version of function f to call because f doesn't take any arguments to specify.
10.2. Traits: Defining Shared Behavior
Traits provide functionality for a particular data type, but also traits can be shared.
traits can be thought of as the functions that can be called on the type, for example:
an integer can be converted to a string by calling the to_string function: 5.to_string() -> "5"
We can declare our own traits:
summary is the name of our trait
Using traits:
in this picture ^^ we import the traits
then we can use the traits on the types we defined them for: println!("1 new tweet: {}", tweet.summarize());
I'm not sure what this means exactly, but I'll leave it here.
so basically, to implement a trait on a type, the trait or the type needs to be local to the crate
for the first question, the program does compile because our trait is local
the make_noise function has a specific definition for the type Dog, but not for cat, so cat uses the generic function
here is the second question:
the only option not selected is an external type and an external trait. At least one of them needs to be local.
basically we can specify the traits for a parameter type. For example, we have to specify the type of a parameter, and it's the same with generic types, but now we can specify that only when a type with matching traits is passed will it satisfy the parameter type
Quiz 2:
Why does it make a difference to change the return type to T?
So basically, we know that the type passed to the function implements display, but we don't know if it implements .push_string.
whatever type is passed as an argument must be able to call .clone() and also must be able to be displayed i.e. printed, so the parameter needs to contain the traits clone + display
Validating References with Lifetimes
every reference has a lifetime, which is the scope that the reference is valid
Dangling References -- when a program references data other than the data it intends
i.e. if something goes out of scope and we try to reference it, it will no longer be valid
Rust uses something called a borrow checker to see if a reference has gone out of scope.
Lifetime parameters have an apostrophe. For example: &'a i32
notice that both the x and y parameters, and the return type, share 'a (the same lifetime). I think this means that the lifetime of x and y are the same as the return value. I'm assuming this means that x and y are still in scope when the return value is returned?
Note!!!
so basically, we aren't creating lifetimes, but we are insuring that the parameters we pass to functions have matching lifetimes so the function doesn't reference out of scope data
life time is equal to the argument with the shortest lifetime passed to a function
a static lifetime ('static) means that a reference lives as long as the program. String literals have a static lifetime by default
It doesn't compile because y will go out of scope because it doesn't have the same lifetimes as the return value
because there is only a single input, the return value is given the same lifetime. This is rule 1.
I don't understand this one, but it says Rust won't compile because it's ambiguous whether the reference @Foo refers to the field bar, or the struct Foo. So does this mean that structs and the fields within a struct have separate lifetimes.
attributes -- meta data about pieces of code
we add #[test] to change a function into a test function
run tests using: cargo test
Macros: assert! checks if a condition is true panic! prints out an error message and ends the program? assert_eq! checks if the value returned from a function is equal to a value assert_ne!
Tests run parallel using multi threading
if we set the number of threads to 1, then the tests one at a time
if we want to run only a subset of the tests then we can specify which tests to run as arguments to cargo test. For example: cargo test one_hundred in this example, only the function named "one_hundred" is tested.