Reading notes - The Rust Programming Language

目录

The Rust Programming Language

Foreword

Introduction

Who rust is for

Who this book is for

How to use this book

Getting started

Installation

Hello world

Hello, cargo

Common programming concepts

Variables and mutability

Data types

Functions

Comments

Control flows

Understanding ownership

What is ownership

References and Borrowing

The slice type

Chapter 5: Using Structs to Structure Related Data

5.1. Defining and Instantiating Structs

5.2. An example Program Using Structs

5.3. Method Syntax

Chapter 6: Enums and pattern matching

6.1. defining an enum

6.2 The match Control Flow Construct

6.3 Concise Control Flow with if let

Summary

Chap 7: Managing Growing Projects with Packages, Crates, and Modules

7.1. Packages and Crates

7.2. Defining Modules to Control Scope and Privacy

7.3. Paths for Referring to an Item in the Module Tree

 

7.4. Bringing Paths Into Scope with the use Keyword

 

7.5. Separating Modules into Different Files

Chaper 8: Common Collections

8.1. Storing lists of values with vectors

8.2. Storing utf-8 encoded text with strings

8.3. Storing keys with associated values in hash maps

Chapter 9. Error Handling

9.1. Unrecoverable Errors with panic!

9.2. Recoverable Errors with Result

9.3. To panic! Or Not to panic!

Chapter 10: generic types, and lifetimes

10.1 generic data types​​​​​​​

10.2 traits: defining shared behavior

10.3 validating references with lifetimes


The Rust Programming Language

  • Book formats: online html, offline

Foreword

  • Rust is fundamentally about empowerment: systems-level works
  • Rust eliminating the old pitfalls and providing a friendly, polished set of tools
  • Rust isn’t limited to low-level systems programming

Introduction

  • Rust challenges that conflict.

Who rust is for

  • Teams of developers
    • Low-level bugs catch by compiler
    • Tools
      • Cargo: dep manager
      • Rustfmt: code formatter
      • Rust Language Server
  • Students: learn system programming
  • Companies: include Firefox browser
  • People who value speed, stability
    • Speed: coding speed, running speed
    • Stability: great compiler's checks

Who this book is for

  • You just need to know programming

How to use this book

  • In sequence from front to back
  • 2 kinds of chapters
    • Concept chapters
    • Project chapters: 2, 12, 20
  • What each chapter about …
  • It is important to understand error messages

Getting started

  • Install rust
  • Program hello world
  • The package manager: cargo

Installation

  • Rust versions manager: rustup
  • Install rustup:
    • $ curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
  • Linker
    • which is a program that Rust uses to join its compiled outputs into one file
  • A C compiler is also useful
    • because some common Rust packages depend on C code and will need a C compiler.
    • Mac:  $ xcode-select --install
    • Ubuntu: build-essential package
  • Update and uninstall rustup
    • Update: $ rustup update
    • Uninstall: $ rustup self uninstall
  • Check rust installation
    • $ rustc --version
  • Documentation
    • rustup doc

Hello world

  • we suggest making a projects directory in your home directory and keeping all your projects there.
  • Rust files always end with the .rs extension
  • underscore to separate worlds
    • use hello_world.rs rather than helloworld.rs.
  • Run it
    • On Windows, enter the command .\main.exe instead of ./main:
  • Anatomy
    • Define function
      • Entry point: main function
      • Fomatter: rustfmt (included with rustc)
      • Indent with 4 spaces, not a tab.
        • 2 spaces works too
      • Macro: !
        • Not same as functions
    • Compiling and running are separate steps
      • Compile with rustc
        • 2 files on linux vs. 3  files on windows

Hello, cargo

  • Cargo is Rust’s build system and package manager.
  • Check it installed: $ cargo --version
  • Create projects with cargo

  • Cargo.toml
    • Reading notes - The Rust Programming Language_第1张图片
    • This file is in the TOML (Tom’s Obvious, Minimal Language) format, which is Cargo’s configuration format.
    • [package]
      • Info about you app
    • [dependencies]
      • For you deps
      • packages of code are referred to as crates
  • Cargo.lock
    • Deps lock file
    • Generated on first build
  • Cargo expects your source files to live inside the src directory
  • Build and run
    • Build
      • his command creates an executable file in target/debug/hello_cargo
    • One step build and run
    • Check only
      • cargo check
    • Build for release
      • This command will create an executable in target/release instead of target/debug.
      • Two modes (profiles): dev and release

Common programming concepts

Variables and mutability

  • By default variables are immutable
  • Explain errors
    • Rustc --explain E0384
  • Define variables
    • Immutable by default: let = ;
    • Mutable: let mut = ;
    • Performance trade off
    • Constants
      • Vs. variables, always immutable
      • Keyword: const
      • Always with type anotation
      • Can be in any scope, including global
      • Value can only be constant expression
      • E.g.: const DAY_SECONDS: u32 = 24 * 60 * 60
      • Naming convertion
      • Valid for the entire app times
    • Shadowing
      • Reading notes - The Rust Programming Language_第2张图片
      • Create a new var indeed, can be diff type

Data types

  • two data type subsets: scalar and compound.
  • Rust is a statically typed language
  • The compiler can usually infer what type we want to use
  • Scalar types
    • A single value
    • 4 primary scalar types
      • Integers
      • Float-point numbers
      • Booleans
      • Characters
    • Integer types
      • Singed vs. unsigned: i vs. u
      • Reading notes - The Rust Programming Language_第3张图片
      • Each signed variant can store numbers from -(2n - 1) to 2n - 1 - 1 inclusive
      • Unsigned variants can store numbers from 0 to 2n - 1
      • the isize and usize types depend on the architecture of the computer
      • integer literals
        • allow a type suffix,
        • use _ as a visual separator
        • Reading notes - The Rust Programming Language_第4张图片
        • integer types default to i32
        • you’d use isize or usize is when indexing some sort of collection.
        • integer overflow can result in one of two behaviors
          • in debug mode, Rust includes checks for integer overflow that cause your program to panic at runtime
          • in release mode, Rust performs two’s complement wrapping, In the case of a u8, the value 256 becomes 0, the value 257 becomes 1,
          • To explicitly handle the possibility of overflow
          • Reading notes - The Rust Programming Language_第5张图片
    • Floating-point types
      • f32 and f64
      • All floating-point types are signed.
      • according to the IEEE-754 standard
    • Numeric operations
      • Integer division rounds down to the nearest integer
      • Reading notes - The Rust Programming Language_第6张图片
    • The boolean type
      • Booleans are one byte in size
      • Reading notes - The Rust Programming Language_第7张图片
    • The character type
      • Reading notes - The Rust Programming Language_第8张图片
      • Rust’s char type is four bytes in size and represents a Unicode Scalar Value
      • your human intuition for what a “character” is may not match up with what a char is in Rust
    • Compound types
      • wo primitive compound types: tuples and arrays.
      • The tuple type
        • Tuples have a fixed length: once declared, they cannot grow or shrink in size.
        • To get the individual values out of a tuple, we can use pattern matching to destructure a tuple value
        • Reading notes - The Rust Programming Language_第9张图片
        • We can also access a tuple element directly by using a period (.) followed by the index
        • Reading notes - The Rust Programming Language_第10张图片
        • The tuple without any values, (), is a special type that has only one value, also written (). The type is called the unit type and the value is called the unit value. Expressions implicitly return the unit value if they don’t return any other value.
      • The array type
        • every element of an array must have the same type
        • arrays in Rust have a fixed length.
        • Arrays are useful when you want your data allocated on the stack rather than the heap
        • An array isn’t as flexible as the vector type, provided by the standard library that is allowed to grow or shrink in size
        • If you’re unsure whether to use an array or a vector, chances are you should use a vector.
        • arrays are more useful when you know the number of elements
        • Here, i32 is the type of each element. After the semicolon, the number 5 indicates the array contains five elements.
        • You can also initialize an array to contain the same value for each element
        • same as writing let a = [3, 3, 3, 3, 3]
        • Invalid Array Element Access
        • Reading notes - The Rust Programming Language_第11张图片
        • The program resulted in a runtime error at the point of using an invalid value in the indexing operation

Functions

  • Snake case: lower case + underscore
  • How to define and call
  • Position not matters
  • Parameters
    • Parameter(def) vs. argument(call)
    • you must declare the type of each parameter
  • Statements and expressions
    • What is the different
    • No: x = (y = 6)
    • Calling a macro is an expression.
    • A new scope block created with curly brackets is an expression
    • Reading notes - The Rust Programming Language_第12张图片
  • Return values
    • You must declare return type: ->
    • The 'return' keyword
    • Last expression for return value
    • Reading notes - The Rust Programming Language_第13张图片
    • () for no return value

Comments

  • Normal: //
  • Doc comments, see chap 14

Control flows

  • If expression
    • Reading notes - The Rust Programming Language_第14张图片
    • Condition need no (), must be type of bool
    • ==, !=
    • combining if and else in an else if expression
    • a powerful Rust branching construct called match
    • If expression, return same type
  • Repeating
    • 3 types: loop, while, for
    • Loop
      • Reading notes - The Rust Programming Language_第15张图片
      • Key words: break, continue
      • Break for returning value
      • Reading notes - The Rust Programming Language_第16张图片
      • Loop labels
        • If you have loops within loops, break and continue apply to the innermost loop at that point
        • Loop labels must begin with a single quote
        • Reading notes - The Rust Programming Language_第17张图片
    • While
      • Reading notes - The Rust Programming Language_第18张图片
      •  compiler adds runtime code to perform the conditional check of whether the index is within the bounds of the array
    • For
      • Reading notes - The Rust Programming Language_第19张图片
      • For Range
      • Reading notes - The Rust Programming Language_第20张图片

Understanding ownership

What is ownership

  • Ownership is Rust’s most unique feature and has deep implications for the rest of the language. It enables Rust to make memory safety guarantees without needing a garbage collector
  • Rust uses a third approach: memory is managed through a system of ownership with a set of rules that the compiler checks. If any of the rules are violated, the program won’t compile. None of the features of ownership will slow down your program while it’s running.
  • The stack and the heap
    • Stack
      • Last in, first out
      • Push, pop
      •  known, fixed size
    • Heap
      • Allocating on the heap
      • Pointer can store on the stack
    • summary
      • Accessing data in the heap is slower than accessing data on the stack
      • Function and stack
      • the main purpose of ownership is to manage heap data
  • Ownership rules
    • Each value in Rust has an owner.
    • There can only be one owner at a time.
    • When the owner goes out of scope, the value will be dropped.
  • Variable scope
    • Similar to other languages
  • The String type
    • String is immutable
    • create a String from a string literal using the from function
    • Op :: for namespace
    • String be mutated but literals cannot
    • Reading notes - The Rust Programming Language_第21张图片
  • Memory and allocation
    •  string literals are fast and efficient, because of fixed size and immutability
    • 2 steps
      • The memory must be requested from the memory allocator at runtime.
      • We need a way of returning this memory to the allocator when we’re done
    • No Garbage collector
      • Rust takes a different path: the memory is automatically returned once the variable that owns it goes out of scope
      • When a variable goes out of scope, Rust calls a special function for us. This function is called drop, and it’s where the author of String can put the code to return the memory. Rust calls drop automatically at the closing curly bracket.
      • Like C++ Resource Acquisition Is Initialization (RAII)
  • Ways variables and data interact: move
    • Two value(5) on the stack
    • Stack and heap
    • Reading notes - The Rust Programming Language_第22张图片
    • The difference between length and capacity matters
      • The length is how much memory, in bytes, the contents of the String is currently using.
      • The capacity is the total amount of memory, in bytes, that the String has received from the allocator.
    • After copying
    • Reading notes - The Rust Programming Language_第23张图片
    • To ensure memory safety, after the line let s2 = s1, Rust considers s1 as no longer valid.
    • You will get an error
    • it’s known as a move
  • Ways variables and data interact: clone
    • If we do want to deeply copy the heap data of the String, we can use a common method called clone
    • It’s a visual indicator that something different is going on
    • Stack-only data: copy
      • Rust has a special annotation called the Copy trait that we can place on types that are stored on the stack, as integers are
      • With copy trait, assignment for copy, not for moving
      • Rust won’t let us annotate a type with Copy if the type, or any of its parts, has implemented the Drop trait. 
      • Here are some of the types that implement Copy:
      • Reading notes - The Rust Programming Language_第24张图片
  • Ownership and functions
    • Passing a variable to a function will move or copy, just as assignment does.
    • Reading notes - The Rust Programming Language_第25张图片
  • Return values and scope
    • Returning values can also transfer ownership
    • Reading notes - The Rust Programming Language_第26张图片
  • Summary
    • The ownership of a variable follows the same pattern every time: assigning a value to another variable moves it. When a variable that includes data on the heap goes out of scope, the value will be cleaned up by drop unless ownership of the data has been moved to another variable.
    • What if we want to let a function use a value but not take ownership
      • Rust has a feature for using a value without transferring ownership, called references.

References and Borrowing

  • References
    • A reference is like a pointer in that it’s an address we can follow to access the data stored at that address; that data is owned by some other variable. Unlike a pointer, a reference is guaranteed to point to a valid value of a particular type for the life of that reference.
  • Reading notes - The Rust Programming Language_第27张图片
  • &: These ampersands represent references, and they allow you to refer to some value without taking ownership of it.
  • Reading notes - The Rust Programming Language_第28张图片
  • Dereference: *
  • the value referenced will not be dropped when the reference stops being used
  • We call the action of creating a reference borrowing
  • We can not change borrowed value
  • Reading notes - The Rust Programming Language_第29张图片
  • Mutable references
    • Reading notes - The Rust Programming Language_第30张图片
    • Mutable references have one big restriction:
      • if you have a mutable reference to a value, you can have no other references to that value.
      • we cannot borrow s as mutable more than once at a time
      • The benefit of having this restriction is that Rust can prevent data races at compile time
      • A data race is similar to a race condition and happens when these three behaviors occur:
        • Two or more pointers access the same data at the same time.
        • At least one of the pointers is being used to write to the data.
        • There’s no mechanism being used to synchronize access to the data.
      • we can use curly brackets to create a new scope, allowing for multiple mutable references
      • Reading notes - The Rust Programming Language_第31张图片
      • Rust enforces a similar rule for combining mutable and immutable references
      • Reading notes - The Rust Programming Language_第32张图片
      • Multiple immutable refs are allowed, no one can change
      • a reference’s scope starts from where it is introduced and continues through the last time that reference is used
      • Reading notes - The Rust Programming Language_第33张图片
      • The ability of the compiler to tell that a reference is no longer being used at a point before the end of the scope is called Non-Lexical Lifetimes (NLL for short)
  • Dangling references
    • dangling pointer--a pointer that references a location in memory that may have been given to someone else--by freeing some memory while preserving a pointer to that memory.
    •  if you have a reference to some data, the compiler will ensure that the data will not go out of scope before the reference to the data does.
    • Reading notes - The Rust Programming Language_第34张图片

  • Reading notes - The Rust Programming Language_第35张图片
  • The Rules of References
    • At any given time, you can have either one mutable reference or any number of immutable references.
    • References must always be valid.

The slice type

  • Slices let you reference a contiguous sequence of elements in a collection rather than the whole collection.
  • A slice is a kind of reference, so it does not have ownership.
  • Think about it:
  • Reading notes - The Rust Programming Language_第36张图片
  • The problem:
  • Reading notes - The Rust Programming Language_第37张图片
  • What about this:
  • Solution: string slices - a reference to part of a string
    • Result = [from, to)
    • Reading notes - The Rust Programming Language_第38张图片
    • Start from 0
    • Go to the end
    • Reading notes - The Rust Programming Language_第39张图片
    • Entire
    • Reading notes - The Rust Programming Language_第40张图片
    • create a string slice in the middle of a multibyte character, your program will exit with an error
    • the type that signifies “string slice” is written as &str
    • Reading notes - The Rust Programming Language_第41张图片
    • Compiler catch the error
    • Reading notes - The Rust Programming Language_第42张图片
    • Why the compiler error:
      • Recall from the borrowing rules that if we have an immutable reference to something, we cannot also take a mutable reference. Because clear needs to truncate the String, it needs to get a mutable reference. The println! after the call to clear uses the reference in word, so the immutable reference must still be active at that point. Rust disallows the mutable reference in clear and the immutable reference in word from existing at the same time, and compilation fails. Not only has Rust made our API easier to use, but it has also eliminated an entire class of errors at compile time!
  • String slices as parameters
    • One more improvement: string slice as param
    • Defining a function to take a string slice instead of a reference to a String makes our API more general and useful without losing any functionality:
    • Reading notes - The Rust Programming Language_第43张图片
    • String literal as string slice already
  • Other slices
    • Reading notes - The Rust Programming Language_第44张图片
    • You’ll use this kind of slice for all sorts of other collections
  • Summary
    • The concepts of ownership, borrowing, and slices ensure memory safety in Rust programs at compile time. The Rust language gives you control over your memory usage in the same way as other systems programming languages, but having the owner of data automatically clean up that data when the owner goes out of scope means you don’t have to write and debug extra code to get this control.

Chapter 5: Using Structs to Structure Related Data

  • Structs and enums
  • Fields and methods

5.1. Defining and Instantiating Structs

  • Define struct with fields
  • Reading notes - The Rust Programming Language_第45张图片
  • Build struct instance
  • Reading notes - The Rust Programming Language_第46张图片
  • Accessing instance
  • Reading notes - The Rust Programming Language_第47张图片
  • Object builder
  • Reading notes - The Rust Programming Language_第48张图片
  • Using the field init shorthand
  • Reading notes - The Rust Programming Language_第49张图片
  • Struct update syntax
  • Reading notes - The Rust Programming Language_第50张图片
    • The user1 must come last
    • Data move apply to fields
  • Tuple struct
  • Reading notes - The Rust Programming Language_第51张图片
    • Name for tuple struct, but not for fields
    • Behave like tuple
  • Unit struct
  • Reading notes - The Rust Programming Language_第52张图片
  • Ownership of struct data
    • Owned type (e.g. String) vs. copy type (e.g. i32)
    • Store references need lifetime

5.2. An example Program Using Structs

  • a program that calculates the area of a rectangle
    • Single width, height
    • Reading notes - The Rust Programming Language_第53张图片
    • With tuple
    • Reading notes - The Rust Programming Language_第54张图片
    • With struct
    • Reading notes - The Rust Programming Language_第55张图片
  • Derived traits
    • We want to print a struct
    • This do not works
    • Reading notes - The Rust Programming Language_第56张图片
    • println! Use 'Display' formatting: output for end user. Primitives got one
    • 'Debug' output format
    • add the outer attribute #[derive(Debug)]
    • Reading notes - The Rust Programming Language_第57张图片
    • Make it a bit easier to read
    • use {:#?} instead of {:?} in the println!
    • Reading notes - The Rust Programming Language_第58张图片
    • Another way to output debug format: dbg!
      • which takes ownership of an expression, prints the file and line number of where that dbg! macro call occurs in your code along with the resulting value of that expression, and returns ownership of the value
      • Reading notes - The Rust Programming Language_第59张图片

  • Reading notes - The Rust Programming Language_第60张图片
  • Rust has provided a number of traits for us to use with the derive attribute
  • Attribute vs. traits

5.3. Method Syntax

  • Unlike functions, methods are defined within the context of a struct (or an enum or a trait object), and their first parameter is always self, which represents the instance of the struct the method is being called on.
  • Reading notes - The Rust Programming Language_第61张图片
  • The &self is actually short for self: &Self
  • Methods must have a parameter named self of type Self for their first parameter
  • Having a method that takes ownership of the instance by using just self is rare:
    • this technique is usually used when the method transforms self into something else and you want to prevent the caller from using the original instance after the transformation.
  • The main reason for using methods instead of functions is for organization
  • we can choose to give a method the same name as one of the struct’s fields
  • Reading notes - The Rust Programming Language_第62张图片
  • Methods like this are called getters
    • etters are useful because you can make the field private but the method public
  • Where’s the -> Operator?
    • In C and C++, two different operators are used for calling methods: you use . if you’re calling a method on the object directly and -> if you’re calling the method on a pointer to the object and need to dereference the pointer first. In other words, if object is a pointer, object->something() is similar to (*object).something().
    • Rust doesn’t have an equivalent to the -> operator; instead, Rust has a feature called automatic referencing and dereferencing
    • Here’s how it works: when you call a method with object.something(), Rust automatically adds in &, &mut, or * so object matches the signature of the method.
  • Methods with More Parameters
    • Add a new method: can_hold
    • Reading notes - The Rust Programming Language_第63张图片

  • Reading notes - The Rust Programming Language_第64张图片
  • Associated Functions
    • All functions defined within an impl block are called associated functions because they’re associated with the type named after the impl. 
    • Like static (type) methods, e.g. String::from
    • Reading notes - The Rust Programming Language_第65张图片
    • To call this associated function, we use the :: syntax with the struct name
  • Multiple impl Blocks
  • Reading notes - The Rust Programming Language_第66张图片

Chapter 6: Enums and pattern matching

6.1. defining an enum

  • How to define
  • Reading notes - The Rust Programming Language_第67张图片
  • How to use
  • Reading notes - The Rust Programming Language_第68张图片

  • Reading notes - The Rust Programming Language_第69张图片
  • Enum with data
  • Reading notes - The Rust Programming Language_第70张图片

  • Reading notes - The Rust Programming Language_第71张图片
  • Standard lib definition
  • Reading notes - The Rust Programming Language_第72张图片
  • Enum vs. struct
  • Reading notes - The Rust Programming Language_第73张图片

  • Reading notes - The Rust Programming Language_第74张图片
  • Enum methods
  • Reading notes - The Rust Programming Language_第75张图片
  • The Option enum
    • Rust has no null feature
    • “Null References: The Billion Dollar Mistake,”
    • included in the prelude, need no import
    • you can use Some and None directly without the Option:: prefix. 
    • Force right usage
    • Reading notes - The Rust Programming Language_第76张图片
    • The Option enum has a large number of methods 
    • The match expression is a control flow construct that does just this when used with enums: it will run different code depending on which variant of the enum it has, and that code can use the data inside the matching value.

6.2 The match Control Flow Construct

  • Patterns can be made up of literal values, variable names, wildcards, and many other things
  • Reading notes - The Rust Programming Language_第77张图片
  • Multi lines
  • Reading notes - The Rust Programming Language_第78张图片
  • Enum with state

  • Reading notes - The Rust Programming Language_第79张图片
  • Matching with Option
  • Reading notes - The Rust Programming Language_第80张图片
  • Matches Are Exhaustive
  • Don't do this
  • Reading notes - The Rust Programming Language_第81张图片
  • Catch-all Patterns and the _ Placeholder
  • Reading notes - The Rust Programming Language_第82张图片
  • Note that we have to put the catch-all arm last
  • when we don’t want to use the value in the catch-all pattern: _
  • _ and unit type
  • Reading notes - The Rust Programming Language_第83张图片

6.3 Concise Control Flow with if let

  • With match
  • Reading notes - The Rust Programming Language_第84张图片
  • With if let
  • Reading notes - The Rust Programming Language_第85张图片
  • lose the exhaustive checking that match enforces. 
  • We can include an else with an if let
  • Reading notes - The Rust Programming Language_第86张图片

Summary

  • When enum values have data inside them, you can use match or if let to extract and use those values

Chap 7: Managing Growing Projects with Packages, Crates, and Modules

  • A package can contain multiple binary crates and optionally one library crate
  • As a package grows, you can extract parts into separate crates that become external dependencies
  • A related concept is scope
    • name conflicts
  • module system
    • Packages
    • Crates
    • Modules, use
    • Paths

 

7.1. Packages and Crates

  • package is one or more crates that provide a set of functionality
  • A package contains a Cargo.toml file that describes how to build those crates.
  • crate can be a binary crate or a library crate
  • Library crates don’t have a main function
  • The crate root is a source file that the Rust compiler starts from and makes up the root module of your crate
  • Several rules:
    • A package can contain at most one library crate
    • It can contain as many binary crates as you’d like
    • but it must contain at least one crate (either library or binary).
  • When we cargo new :
    • Cargo created a Cargo.toml file, giving us a package
    • Cargo follows a convention that src/main.rs is the crate root of a binary crate with the same name as the package.
    • Cargo knows that if the package directory contains src/lib.rs, the package contains a library
    • If a package contains src/main.rs and src/lib.rs, it has two crates
    • A package can have multiple binary crates by placing files in the src/bin directory

7.2. Defining Modules to Control Scope and Privacy

  • Modules Quick Reference
    • Start from the crate root
    • Declaring submodules
      • In any file other than crate root
      • Places of module (mod vegetables) code
        • Inline
        • In the file src/garden/vegetables.rs
        • In the file src/garden/vegetables/mod.rs
    • Paths to code in modules
      • crate::garden::vegetables::Asparagus
    • Private vs. public
      • Public module: pub mod
      • Pub item
    • The use keyword
      • the use keyword creates shortcuts to items to reduce repetition of long paths
    • Module example
    • Reading notes - The Rust Programming Language_第87张图片

  • Reading notes - The Rust Programming Language_第88张图片
  • The pub mod garden; tells the compiler includes the code

  • Grouping Related Code in Modules
    • Module for code grouping, privacy control
    • Create a new library named restaurant by running cargo new --lib restaurant
    • Reading notes - The Rust Programming Language_第89张图片

  • Reading notes - The Rust Programming Language_第90张图片
  • Notice that the entire module tree is rooted under the implicit module named crate.

7.3. Paths for Referring to an Item in the Module Tree

  • A path can take two forms:
    • An absolute path starts from a crate root by using a crate name (for code from an external crate) or a literal crate (for code from the current crate).
    • relative path starts from the current module and uses selfsuper, or an identifier in the current module.
  • ::
  • Path examples, not work
  • Reading notes - The Rust Programming Language_第91张图片
  • we can use the crate keyword to start an absolute path
  • Start from 'crate' like '/'
  • Absolute vs. relative
    • Relative for: consumer together with module
    • Absolute for: otherwise
  • Module for privacy boundary
    • All items of module are private by default
    • Items in child module can use parent items
  • Exposing Paths with the pub Keyword
  • Reading notes - The Rust Programming Language_第92张图片
    • Make 'pub' all the way to the item
    • Can ref siblings
    • The Rust API Guidelines
  • Best Practices for Packages with a Binary and a Library
    • 2 crate: bin + lib
    • 'lib' used by bin, and other projects as well
  • Starting Relative Paths with super
    • 'super' like '..', for parent module
  • Making Structs and Enums Public
    • 'pub' for struct and its fields
    • Reading notes - The Rust Programming Language_第93张图片
    • A struct has a private field, need a public function for constructing instances
    • In contrast, if we make an enum public, all of its variants are then public. We only need the pub before the enum keyword,
    • Reading notes - The Rust Programming Language_第94张图片

 

7.4. Bringing Paths Into Scope with the use Keyword

  • 'use' keyword for shorter module ref
    • Reading notes - The Rust Programming Language_第95张图片
    • Also check privacy
    • Only valid in same scope, below not work
    • Reading notes - The Rust Programming Language_第96张图片

 

  • How to fix:
    • move the use within the customer module
    • super::hosting
  • Creating Idiomatic use Paths
    • Idiomatic: 'use all::the::way::to::module'
    • unidiomatic: 'use all::the::way::to::module::item'
    • Idiomatic make it clear where items from
    • Idiomatic for fns, unidiomatic for struct, enum, etc.
    • Idiomatic for items with same names
    • Reading notes - The Rust Programming Language_第97张图片
  • Providing New Names with the as Keyword
    • Reading notes - The Rust Programming Language_第98张图片
  • Re-exporting Names with pub use
    • Reading notes - The Rust Programming Language_第99张图片
    • Re-exporting is useful when the internal structure of your code is different from how programmers calling your code would think about
  • Using External Packages
    • To use a external package
    • Download deps from crates.io, make it usable
    • Reading notes - The Rust Programming Language_第100张图片
    • Intermedia modules are also available
    • The 'std' starndard lib
    • Package > crate > module > item
  • Using Nested Paths to Clean Up Large use Lists
    • Reading notes - The Rust Programming Language_第101张图片
    • Use 'self'
  • The Glob Operator
    • Note: Glob can make it harder to tell what names are in scope
    • often used when testing to bring everything under test into the tests module

7.5. Separating Modules into Different Files

  • Before, we have all the modules in the crate root file, src/lib.rs
  • We can put them in multiple files, so do the binary crate, src/main.rs
  • How to do
    • Reading notes - The Rust Programming Language_第102张图片
    • The compiler knows to look in this file because of the module declaration
    • Reading notes - The Rust Programming Language_第103张图片
    • Using 'mod' declaration to load file, 'mod' is not an 'include'
    • One 'mod', many 'use'
    • Module should be place in where named for its place in the module tree
    • Module: crate::front_of_house::hosting
    • file path for modules
      • 'src/my_module.rs (idiomatic)
      • 'src/my_module/mod.rs (also support)
      • Use both will get error
      • 'mod.rs' is not good for open multiple
  • 'mod', 'use', 'pub'

Chaper 8: Common Collections

  • Standard lib has many collection type
  • Choose the right one

8.1. Storing lists of values with vectors

  • Data type: vector
    • Code: Vec
    • Put values next to each other in memory
    • Store values of the same type
  • Creating a new vector
    • Need type annotation for item type if no initial value
    • Macro: vec!
    • Default integer type: i32
  • Updating a vector
    • Use the 'push' method
    • Reading notes - The Rust Programming Language_第104张图片
    • Make it mutable by 'mut'
    • Defer type infers
  • Dropping a vector drops its items
    • Reading notes - The Rust Programming Language_第105张图片
  • Reading elements of vectors
    • 2 ways to reference vector item
      • Indexing
      • 'get' method
    • Reading notes - The Rust Programming Language_第106张图片
    • Index start from 0
    • $v[2] get reference; v.get(2) get Option<&T>
    • Different behaviors when out of index, not compile
      • Indexing will get panic (error)
      • 'get()' return None without panic
      • The borrow checker enforces the ownership and borrowing rules
      • Reading notes - The Rust Programming Language_第107张图片

  • Why don't compile?
  • Reading notes - The Rust Programming Language_第108张图片
  • Iterating over the values in a vector
    • Mutable
    • Use the '*' dereference operator
  • Using an enum to store multiple types
    • Reading notes - The Rust Programming Language_第109张图片
    • Enum variants are considered the same type
    • All vector items must be the same type

8.2. Storing utf-8 encoded text with strings

  • Why new comer stuck on strings
    • Rust intend to exposing possible errors
    • Utf-8
  • What is a string
    • Only on string type in the core
      • String slice: 'str'
      • Usually seen in borrowed form '&str'
      • String literals in code stored in the program's bin, so they are string slice
    • The 'String' type in the standard library
      • Language core vs. standard library
      • a growable, mutable, owned, UTF-8 encoded string type
    • Other standard string types
      • Like 'OsString', 'OsStr', 'Cstring', CStr'
      • 'string' for owned, 'str' for borrowed
  • Creating a new string
    • Many same ops as Vec
    • 'str' to 'string': 'Display' trait for 'to_string()'
    • Reading notes - The Rust Programming Language_第110张图片

  • Updating a string
    • '+' op, 'format!' macro
    • Appending a string with 'push_str' and 'push'
      • 'push_str' will not take ownership
        • Reading notes - The Rust Programming Language_第111张图片
        • If the push_str method took ownership of s2, we wouldn’t be able to print its value on the last line.
      • 'push' a single char
      • Concatenation with '+' or 'format!'
        • The '+' op dep on 'add' method
        • Rust 'coerce' &string to &str, 'deref coercion'
        • Take ownership of s1, borrowed s2, return ownership of the result
        • 'format!': generated code use references
        • Reading notes - The Rust Programming Language_第112张图片
    • Indexing into strings
      • You will get error
      • Internal string representation
        • A String is a wrapper over a Vec.
          • The length is 24, not 12
          • You will get 208
      • Bytes and Scalar Values and Grapheme Clusters! Oh My!
        • Another point about UTF-8 is that there are actually three relevant ways to look at strings from Rust’s perspective: as bytes, scalar values, and grapheme clusters (the closest thing to what we would call letters).
        • Word 'नमस्ते'
          • Storage
          • As 'char' type
          • As grapheme cluster
        • Indexing strings is not O(1)
  • Slicing strings
    • Get first 4 bytes, which is 'Зд'
    •  try to slice only part of a character’s bytes will get compiler error, like &hello[0..1]
  • Methods for Iterating Over Strings
    • 'chars()'
    • 'bytes()'
    • Get grapheme is not provided by standard lib, maybe the crates.io

8.3. Storing keys with associated values in hash maps

  • HashMap
  • Creating a new hash map
    • Reading notes - The Rust Programming Language_第113张图片
    • No preclude
    • Key, value must be of the same type
    • Use collect()
    • Reading notes - The Rust Programming Language_第114张图片
  • Hash maps and ownership
    • Reading notes - The Rust Programming Language_第115张图片
    • A reference must be valid for using
  • Accessing values in a hash map
    • Reading notes - The Rust Programming Language_第116张图片
    • 'score' will be Some(&10)
    • Iterate hash map
    • Reading notes - The Rust Programming Language_第117张图片
  • Updating a hash map
    • What if a key exist when we want to update
    • Overwriting a value
      • Reading notes - The Rust Programming Language_第118张图片
      • Will get {"Blue": 25}
    • Only inserting a value if the key has no value
      • Reading notes - The Rust Programming Language_第119张图片
      • 'entry', 'or_insert' return mutable ref
    • Updating a value based on the old value
      • Reading notes - The Rust Programming Language_第120张图片
      • This code will print {"world": 2, "hello": 1, "wonderful": 1}
    • Hashing functions
      • Default to 'SipHash' for Dos attacks
      • Use can use your own

Chapter 9. Error Handling

  • Some errors are reported before compiling
  • 2 error category
    • Recoverable
      • Like file not found
      • Report the problem to users
    • Unrecoverable
      • Like out of array index
      • Stop the program
  • Rust do not have exceptions
    • Has type Result for the recoverable
    • The panic! Macro for the unrecoverable

9.1. Unrecoverable Errors with panic!

  • What panic! Do
    • Print a failure message
    • Clean up the stack
    • Quit the app
  • Response to a panic
    • Unwinding
      • Clean up
      • A lot of works
    • Aborting
      • Clean up by the OS
      • Config in 'Cargo.toml'
  • Have a try
    • Reading notes - The Rust Programming Language_第121张图片
  • Using a panic! Backtrace
    • Try: reading an invalid index
      • Reading notes - The Rust Programming Language_第122张图片
      • In C, buffer overread
      • Rust will stop execute
    • How to read backtrace
      • From the top util your file
    • Get backtrace
      • Debug symbols must be enable
        • By default when 'cargo build' or 'cargo run' without --release

9.2. Recoverable Errors with Result

  • The 'Result' enum
  • Example
    • Reading notes - The Rust Programming Language_第123张图片

  • Reading notes - The Rust Programming Language_第124张图片
  • Matching on different errors
    • Reading notes - The Rust Programming Language_第125张图片
  • Shortcuts for panic on error: unwrap and expect
    • Reading notes - The Rust Programming Language_第126张图片

  • Reading notes - The Rust Programming Language_第127张图片
  • Propagating errors
    • return the error to the calling code, they might have more info
    • Reading notes - The Rust Programming Language_第128张图片
  • The ? Operator
    • Reading notes - The Rust Programming Language_第129张图片
    • Use the 'from' function
    • Reading notes - The Rust Programming Language_第130张图片

  • Reading notes - The Rust Programming Language_第131张图片
  • Where to use it
    • The ? operator can only be used in functions whose return type is compatible with the value the ? is used on
    • Don't do this
    • Reading notes - The Rust Programming Language_第132张图片
    • Type implement trait 'FromResidual'
  • Use '?' with Option
    • The ? extracts the string slice, and we can call chars on that string slice
  • Luckily, main can also return a Result<(), E>
  • Reading notes - The Rust Programming Language_第133张图片
  • Box for all error types
  • Main fn return 0 for success, otherwise for failure

9.3. To panic! Or Not to panic!

  • Returning 'Result' is a good default choice
  • Use panic! For examples, prototype, tests
  • When you have more info than compiler
    • Reading notes - The Rust Programming Language_第134张图片
  • Guidelines for error handling
    • 'panic' for bad state
    • 'Result' for expected error
    • 'panic' for function contracts violations
    • Use types for check by compiler
    • Reading notes - The Rust Programming Language_第135张图片

Chapter 10: generic types, and lifetimes

  • Unknown parameter types are like unknown parameter values
  • Removing Duplication by Extracting a Function
    • Generic allow to remove code duplication
    • Reading notes - The Rust Programming Language_第136张图片
    • What if we have 2 number list
    • Reading notes - The Rust Programming Language_第137张图片
    • Duplicate code is bad, you need to remember update every one
    • &[i32]: slice of i32 values
    • Pattern matching: for &item in list

10.1 generic data types

  • In function definitions
    • T as type parameter name
    • Reading notes - The Rust Programming Language_第138张图片
    • Do not work, not any type can be ordered
  • In struct definitions
    • Reading notes - The Rust Programming Language_第139张图片
    • 'x', 'y' must be the same type
    • Reading notes - The Rust Programming Language_第140张图片
    • No too much type parameters
  • In enum definitions
  • In method definitions
    • Reading notes - The Rust Programming Language_第141张图片

  • Only Point get this method
  • Methods can have own generics
  • Performance
    • using generic types won't make your run any slower than it would with concrete types.
    • Monomorphization at compile time
    • Reading notes - The Rust Programming Language_第142张图片

10.2 traits: defining shared behavior

  • A trait defines functionality a particular type has and can share with other types.
    • We can use traits to define shared behavior in an abstract way
    • We can use trait bounds to specify that a generic type can be any type that has certain behavior.
    • Traits are similar to a feature often called interfaces in other languages
  • Defining a trait
  • Implementing a trait on a type
    • Reading notes - The Rust Programming Language_第143张图片
    • How to use traits
    • Reading notes - The Rust Programming Language_第144张图片
    • we can implement a trait on a type only if at least one of the trait or the type is local to our crate. 'coherence'
  • Default implementations
    • Give default implements for some methods of trait

  • Reading notes - The Rust Programming Language_第145张图片

  • The syntax for overriding or implementing are the same
  • Use other methods
  • Implement only required methods
  • Reading notes - The Rust Programming Language_第146张图片
  • Can not call the default implementation
  • Traits as parameters
    • Reading notes - The Rust Programming Language_第147张图片
    • Item is something implements the Summary trait
  • Trait bound syntax
    • Longer form for the above syntax sugar
    • Item1 and item2 can be different type
    • Reading notes - The Rust Programming Language_第148张图片
    • Must be the same type
  • + multiple trait bounds
    • Item is something implement 'Summary' and 'Display'
  • Trait bounds with 'where'
  • Returning types that implement traits
    • Reading notes - The Rust Programming Language_第149张图片
    • Useful for closures and iterators
    • Don't do this
    • Reading notes - The Rust Programming Language_第150张图片
  • Using Trait Bounds to Conditionally Implement Methods
    • Blanket implementations
      • Implement ToString for types of 'Display'
    • So we got the to_string() on many types

10.3 validating references with lifetimes

  • Intro
    • Every reference has a lifetime
    • Sometimes we must annotate lifetimes
    • generic lifetime parameters
  • Dangling references
    • 'x' dead before r be used
  • The borrow checker
    • Longer life use a shorter life
  • Generic lifetimes in functions
    • Reading notes - The Rust Programming Language_第151张图片
    • This will get error

  • Reading notes - The Rust Programming Language_第152张图片
  • Lifetime annotation syntax
  • Lifetime annotations in function signatures
    • Reading notes - The Rust Programming Language_第153张图片
    • Helpful for compiler to point out errors
    • Use the smaller lifetime scope
    • Do not compile
  • Thinking in terms of lifetimes
    • When returning a reference from a function, the lifetime parameter for the return type needs to match the lifetime parameter for one of the parameters
    • Do not return refs of local variables 
    • the best fix would be to return an owned data type
    • Ultimately, lifetime syntax is about connecting the lifetimes of various parameters and return values of functions.
  • Lifetime annotations in struct definitions
    • Reading notes - The Rust Programming Language_第154张图片
    • This annotation means an instance of ImportantExcerpt can’t outlive the reference it holds in its partfield.
  • Lifetime elision
    • The patterns programmed into Rust’s analysis of references are called the lifetime elision rules
    • Lifetimes on function or method parameters are called input lifetimes, and lifetimes on return values are called output lifetimes.
    • three rules to figure out the lifetimes of the references
      • the compiler assigns a lifetime parameter to each parameter that’s a reference (a function with two parameters gets two separate lifetime parameters)
      • if there is exactly one input lifetime parameter, that lifetime is assigned to all output lifetime parameters: fn foo<'a>(x: &'a i32) -> &'a i32.
      • the lifetime of self is assigned to all output lifetime parameters
  • Lifetime annotations in method definitions
    • Reading notes - The Rust Programming Language_第155张图片

  • The static lifetime
    • Live for life long
    • When compiler suggest 'static lifetime, check if we can fix without it
  • All together
    • Reading notes - The Rust Programming Language_第156张图片

你可能感兴趣的:(IT,阅读笔记,rust,开发语言)