<aside> 💡 Note: You won’t just know which traits to use and which methods and functions to call from a crate, so each crate has documentation with instructions for using it. Another neat feature of Cargo is that running the cargo doc --open command will build documentation provided by all your dependencies locally and open it in your browser. If you’re interested in other functionality in the rand crate, for example, run cargo doc --open and click rand in the sidebar on the left.

</aside>

<aside> 💡 Ensuring Reproducible Builds with the Cargo.lock File

Cargo has a mechanism that ensures you can rebuild the same artifact every time you or anyone else builds your code: Cargo will use only the versions of the dependencies you specified until you indicate otherwise. For example, say that next week version 0.8.6 of the rand crate comes out, and that version contains an important bug fix, but it also contains a regression that will break your code. To handle this, Rust creates the Cargo.lock file the first time you run cargo build, so we now have this in the guessing_game directory.

When you build a project for the first time, Cargo figures out all the versions of the dependencies that fit the criteria and then writes them to the Cargo.lock file. When you build your project in the future, Cargo will see that the Cargo.lock file exists and will use the versions specified there rather than doing all the work of figuring out versions again. This lets you have a reproducible build automatically. In other words, your project will remain at 0.8.5 until you explicitly upgrade, thanks to the Cargo.lock file. Because the Cargo.lock file is important for reproducible builds, it’s often checked into source control with the rest of the code in your project.

</aside>

<aside> 💡 **The Stack and the Heap But in a systems programming language like Rust, whether a value is on the stack or the heap affects how the language behaves and why you have to make certain decisions.**

Both the stack and the heap are parts of memory available to your code to use at runtime, but they are structured in different ways. The stack stores values in the order it gets them and removes the values in the opposite order. This is referred to as last in, first out.

All data stored on the stack must have a known, fixed size. Data with an unknown size at compile time or a size that might change must be stored on the heap instead.

The heap is less organized: when you put data on the heap, you request a certain amount of space. The memory allocator finds an empty spot in the heap that is big enough, marks it as being in use, and returns a pointer, which is the address of that location. This process is called allocating on the heap and is sometimes abbreviated as just allocating (pushing values onto the stack is not considered allocating). Because the pointer to the heap is a known, fixed size, you can store the pointer on the stack, but when you want the actual data, you must follow the pointer

Pushing to the stack is faster than allocating on the heap because the allocator never has to search for a place to store new data; that location is always at the top of the stack

Accessing data in the heap is slower than accessing data on the stack because you have to follow a pointer to get there. Keeping track of what parts of code are using what data on the heap, minimizing the amount of duplicate data on the heap, and cleaning up unused data on the heap so you don’t run out of space are all problems that ownership addresses.

</aside>


<aside> 📌 Create a new library named restaurant by running cargo new restaurant --lib.

</aside>

we mentioned that src/main.rs and src/lib.rs are called crate roots. The reason for their name is that the contents of either of these two files form a module named crate at the root of the crate’s module structure, known as the module tree.


crate
 └── front_of_house
     ├── hosting
     │   ├── add_to_waitlist
     │   └── seat_at_table
     └── serving
         ├── take_order
         ├── serve_order
         └── take_payment


<aside> 📢 we store that mutable reference in the count variable, so to assign to that value, we must first dereference count using the asterisk (*).

</aside>


<aside> 💡 Semantic Versioning

Read more - https://semver.org/

Given a version number MAJOR.MINOR.PATCH, increment the:

  1. MAJOR version when you make incompatible API changes
  2. MINOR version when you add functionality in a backward compatible manner
  3. PATCH version when you make backward compatible bug fixes

Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.

</aside>

<aside> 💡 About Cargo:

</aside>


<aside> 📌 assert_eq!() ⇒ It quits the program with panick if arguments are not same

</aside>

fn main() {

    let a = [1,2,3,4,5,6];

    // Slicing works with array same as string literals
    
    let arr_slice = &a[1..3];

    assert_eq!(arr_slice, &[2,3]);
}

In his 2009 presentation “Null References: The Billion Dollar Mistake,” Tony Hoare, the inventor of null, has this to say:

I call it my billion-dollar mistake. At that time, I was designing the first comprehensive type system for references in an object-oriented language. My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.


In Rust, .to_owned() is a method that creates an owned version of a borrowed data type, typically used with string slices (&str) or other borrowed types. Let's break down its usage and purpose:

Usage:

.to_owned() is often used in Rust when you need to convert a borrowed value into an owned value. It's particularly common when dealing with string manipulation, where you might start with a borrowed string slice (&str) but need to convert it into an owned String for further processing or storage.

Example:


fn main() {
    let borrowed_string: &str = "Hello, World!";

    // Convert the borrowed string into an owned String
    let owned_string: String = borrowed_string.to_owned();

    // Now `owned_string` holds an owned copy of the original borrowed string
    println!("{}", owned_string);
}

Explanation:

Alternatives:

Performance Considerations:

In summary, .to_owned() in Rust is a method used to convert borrowed types into owned types, commonly used with string slices (&str) to create owned String instances. It's a powerful tool for managing ownership and data lifetimes in Rust programs.




Quick Learnings:

  1. match the Err(_) pattern in the second arm. The underscore, _, is a catchall value; in this example, we’re saying we want to match all Err values, no matter what information they have inside them
  2. By default, Rust has a set of items defined in the standard library that it brings into the scope of every program. This set is called the *prelude*, and you can see everything in it in the standard library documentation.
  3. You need to know that, like variables, references are immutable by default. Hence, you need to write &mut guess rather than &guess to make it mutable.
  4. In Rust, variables are immutable by default, meaning once we give the variable a value, the value won’t change. To make a variable mutable, we add mut before the variable name:
  5. The :: syntax in the ::new line indicates that new is an associated function of the String type. An associated function is a function that’s implemented on a type, in this case String.
  6. The full job of read_line is to take whatever the user types into standard input and append that into a string (without overwriting its contents), so we therefore pass that string as an argument. The string argument needs to be mutable so the method can change the string’s content.
  7. The & indicates that this argument is a reference, which gives you a way to let multiple parts of your code access one piece of data without needing to copy that data into memory multiple times.
  8. Result is an enumeration, often called an enum, which is a type that can be in one of multiple possible states. We call each possible state a variant. Result’s variants are Ok and Err.