< 返回博客

rdigua 发表于 2019-04-15 00:09

Tags:life,tyro,novice,learning

Learning the rust book

Beginning Rust From Novice to Professional

ebook

Why deterministic and implicit destruction of objects is a big plus of Rust


Preface Who this book is for What this book covers To get the most out of this book Download the color images Download the example code files Conventions used Get in touch Reviews

1. Printing on the Terminal

In this chapter, you will learn:

  • How to write and run your first program in the Rust Language
  • How to output texts and numbers on the terminal
  • How to write a small script that makes more readable the output of the compiler // What is its mean?
  • How to write comments in your code
clear
rustc $* --color always 2>&1 | more

This script first clears the screen, then runs the rustc compiler with all the arguments you give to it. If the compilation is successful, or if it generates less than a screenful of error messages, it behaves like a normal run of rustc.

2. Doing Arithmetic

In this chapter, you will learn:

  • How to compute an arithmetic operation between integer numbers or between floating-point numbers
  • How to write a program containing several statements
  • How to print strings in several lines
fn main() {
println!("{}", "This \
is \
just one line");
}

This will print: This is just one line

fn main() {
println!("{}", "These
are
three lines");
}
or this:
fn main() {
println!("{}", "These\n\
are\n\
three lines");
}

Both will print: These are three lines

3. Naming Objects

In this chapter, you will learn:

  • The concepts of “value”, “object”, and “variable”
  • The concept of “mutability” of variables
  • The difference between initialization and re-assignment
  • How to avoid warnings for unused variables
  • The concept of “Boolean expression”
  • Which type checks are performed by the compiler for assignments
  • How some operators can perform both an arithmetic operation and an assignment
  • How to invoke functions defined in the Rust standard library
let _ = 12;
print!("{}", _)
let truth = 5 > 2;
let falsity = -12.3 >= 10.;
print!("{} {} {}", truth, falsity, -50 < 6);
//This will print true false true.

• ==: is equal to • !=: is different from • <: is less than • <=: is less than or equal to • >: is greater than • >=: is greater than or equal to

print!("{} {} {}", "abc" < "abcd", "ab" < "ac", "A" < "a");
//This will print true true true.
let truth = true;
let falsity = false;
println!("{} {}", ! truth, ! falsity);
println!("{} {} {} {}", falsity && falsity, falsity && truth,
truth && falsity, truth && truth);
println!("{} {} {} {}", falsity || falsity, falsity || truth,
truth || falsity, truth || truth);

//This will print: false true false false false true false true true true

print!("{} {}", true || true && ! true,
(true || true) && ! true);

This will print: "true false".

4. Controlling Execution Flow

In this chapter, you will learn: • How to use if statements to execute different statements based on a Boolean condition • How to use if expressions to generate different values based on a Boolean condition • How to use while statements to repeat some statements as long as a Boolean condition holds • How to use for statements to repeat some statements for a definite number of times • What is the scope of validity of variables

5.Using Data Sequences

In this chapter, you will learn: • How to define sequences of objects of the same type, having fixed-length (arrays) or variable-length (vectors)
• How to specify the initial contents of arrays or vectors, by listing the items, or by specifying one item and its repeat count
• How to read or write the value of single items of arrays or vectors
• How to add items to a vector or to remove items from a vector
• How to create arrays with several dimensions
• How to create empty arrays or vectors
• How to print or copy whole arrays or vectors

Multidimensional Arrays

let mut x = [[[[23; 4]; 6]; 8]; 15];
x[14][7][5][3] = 56;
print!("{}, {}", x[0][0][0][0], x[14][7][5][3]);
//This will print: "23, 56."
let x = [[[[0; 4]; 6]; 8]; 15];
print!("{}, {}, {}, {}.",
x.len(), x[0].len(), x[0][0].len(), x[0][0][0].len());
//This will print: "15, 8, 6, 4."

Vectors

To create sequences of objects whose size is defined at runtime, the Rust standard library provides the Vec type, shorthand for vector.

let x = vec!["This", "is"];
print!("{} {}. Length: {}.", x[0], x[1], x.len());
//This will print: "This is. Length: 2."

6. Using Primitive Types

In this chapter, you will learn: • How to write numeric literals in hexadecimal, octal, or binary notation
• How to use the underscore character to make numeric literals easier to read
• How to use the exponential notation to write huge or tiny numbers in a compact form
• Which are the ten primitive integer numeric types, and the two primitive floating-point numeric types; which are their ranges; and when it is better to use each of them
• How to specify numeric literals of concrete types or of unconstrained types • How to convert a numeric value to another numeric type
• The other primitive types: Booleans, characters, and empty tuples
• How type inference works
• How to express the types of arrays and vectors
• How to assign a name to a compile-time constant
• How to use the compiler to discover the type of an expression

let a: i16 = 12;
let b: u32 = 4;
let c: f32 = 3.7;
print!("{}", a as i8 + b as i8 + c as i8);
//This will print: "19".  
let a = 500 as i8;  //..............**..**..??......**..**..??......**..**..??......**..**..??......**..**..??......**..**..??...
let b = 100_000 as u16;
let c = 10_000_000_000 as u32;
print!("{} {} {}", a, b, c);
//Perhaps surprisingly, it will print: "-12 34464 1410065408".

let _: i8 = 127; let _: i16 = 32_767; let _: i32 = 2_147_483_647; let _: i64 = 9_223_372_036_854_775_807; let _: isize = 100; // The maximum value depends on the target architecture let _: u8 = 255; let _: u16 = 65_535; let _: u32 = 4_294_967_295; let _: u64 = 18_446_744_073_709_551_615; let _: usize = 100; // The maximum value depends on the target architecture let _: f32 = 1e38; let _: f64 = 1e308;

let a: () = ();
let b = { 12; 87; 283 };
let c = { 12; 87; 283; };
let d = {};
let e = if false { };
let f = while false { };
print!("{:?} {:?} {:?} {:?} {:?} {:?}",
a, b, c, d, e, f);
//This code will print: "() 283 () () () ()".

7. Enumerating Cases

In this chapter, you will learn:
• How enums help in defining variables that can take on values only from a finite set of cases • How enums can be used to implement discriminated union types • How to use the match pattern-matching construct to handle enums • How to use the match construct to handle other data types, like integer numbers, strings, and single characters • How to use Boolean guards to generalize the pattern-matching of the match construct

enum CardinalPoint { North, South, West, East };
let direction = CardinalPoint::South;
match direction {
CardinalPoint::North => print!("NORTH"),
CardinalPoint::South => print!("SOUTH"),
_ => {},
}

error:

enum CardinalPoint { North, South, West, East };
let direction = CardinalPoint::South;
match direction {
CardinalPoint::North => print!("NORTH"),
_ => {},
CardinalPoint::South => print!("SOUTH"),
}
enum Result {
Success(f64),
Failure(u16, char),
Uncertainty,
}
let outcome = Result::Success(23.67);
match outcome {
Result::Success(_) => print!("OK"),
Result::Failure(error_code, module) =>
print!("Error n. {} in module {}",
error_code, module),
Result::Uncertainty => {},
}
//This will print: "OK".
enum CardinalPoint { North, South, West, East };
let direction = CardinalPoint::South;
print!("{}", match direction {
CardinalPoint::North => 'N',
CardinalPoint::South => 'S',
_ => '*',
});
//This will print: "S."
for n in -2..5 {
println!("{} is {}.", n, match n {
0 => "zero",
1 => "one",
_ if n < 0 => "negative",
_ => "plural",
});
}

This program will print: -2 is negative. -1 is negative. 0 is zero. 1 is one. 2 is plural. 3 is plural. 4 is plural.

MarkP95 P95

8. Using Heterogeneous Data Structures

In this chapter you will learn how to define and use other composite types: • Tuples • Structs • Tuple-Structs They are useful to group objects of different types. At the end of the chapter, you'll see some code style conventions.

const MAXIMUM_POWER: u16 = 600;
enum VehicleKind {
    Motorcycle,
    Car,
    Truck,
}
struct VehicleData {
    kind: VehicleKind,
    registration_year: u16,
    registration_month: u8,
    power: u16,
}
let vehicle = VehicleData {
    kind: VehicleKind::Car,
    registration_year: 2003,
    registration_month: 11,
    power: 120,
};
if vehicle.power > MAXIMUM_POWER {
      println!("Too powerful");
}

9 Defining Functions

In this chapter you will learn: • How to define your own procedures (better known as “functions”) and how to invoke them • When and how you can have several functions with the same name • How to pass arguments to a function, by-value or by-reference • How to return simple and composite values from a function • How to exit prematurely from a function • How references to objects can be manipulated

fn f1() { print!("1"); }
fn main() {
    f1();
    fn f2() { print!("2"); }
    f2(); f1(); f2();
}
// This will print: "1212".  

fn f() { print!("1"); } //it is not used.
fn main() {
    f(); // Prints 2
    {
        f(); // Prints 3
        fn f() { print!("3"); }
    }
    f(); // Prints 2
    fn f() { print!("2"); }
}
//This will print 232.

fn double(x: f64) -> f64 { x * 2. }
print!("{}", double(17.3));
//This will print "34.6".

10. Defining Generic Functions and Structs

// Library code
fn f<T>(ch: char, num1: T, num2: T) -> T {
if ch == 'a' { num1 }
else { num2 }
}
// Application code
let a: i16 = f::<i16>('a', 37, 41);
let b: f64 = f::<f64>('b', 37.2, 41.1);
print!("{} {}", a, b);
//This will print 37 41.1.

// Library code
fn f<T>(ch: char, num1: T, num2: T) -> T {
if ch == 'a' { num1 }
else { num2 }
}
// Application code
let a: i16 = f('a', 37, 41);
let b: f64 = f('b', 37.2, 41.1);
print!("{} {}", a, b);

11. Allocating Memory

In this chapter, you will learn: • The various kinds of memory allocation, their performance characteristics, and their limitations • How to specify in Rust which memory allocation to use for an object • The difference between a reference and a Box

https://www.dyike.com/2018/09/24/rust-box-tree/

https://kaisery.github.io/trpl-zh-cn/ch15-01-box.html

#[derive(Default)]
struct Tree {
  root: i64,
  left: Option<Box<Tree>>,
  right: Option<Box<Tree>>,
}
impl Tree {
  fn new(root: i64) -> Tree {
    Tree {
      root: root,
      ..Default::default()
    }
  }
  fn left(mut self, leaf: Tree) -> Self {
    self.left = Some(Box::new(leaf));
    self
  }
  fn right(mut self, leaf: Tree) -> Self {
    self.right = Some(Box::new(leaf));
    self
  }
}

//...
Tree::new(12)
  .left(
    Tree::new(10)
      .right(Tree::new(14))
  )
  .right(
    Tree::new(16)
      .left(Tree::new(15))
      .right(Tree::new(22))
  );

12. Data Implementation

In this chapter, you will learn: • How to know how many bytes of stack are taken by objects of various types • How to shorten the path to access functions declared in external modules • How bits are stored in primitive type objects • How to know where an object is stored in memory • Why padding can increase the size taken by some objects • How vectors are implemented

use std::mem::*;
print!("{} {} {} {} {} {} {} {} {} {} {} {}",
size_of::<i8>(),
size_of::<u8>(),
size_of::<i16>(),
size_of::<u16>(),
size_of::<i32>(),
size_of::<u32>(),
size_of::<i64>(),
size_of::<u64>(),
size_of::<f32>(),
size_of::<f64>(),
size_of::<bool>(),
size_of::<char>());
In any computer, this will print 1 1 2 2 4 4 8 8 4 8 1 4.
let mut v = vec![0; 0];
println!("{} {}", v.len(), v.capacity());
v.push(11);
println!("{} {}", v.len(), v.capacity());
v.push(22);
println!("{} {}", v.len(), v.capacity());
v.push(33);
println!("{} {}", v.len(), v.capacity());
v.push(44);
println!("{} {}", v.len(), v.capacity());
v.push(55);
println!("{} {}", v.len(), v.capacity());

This will print: 0 0 1 4 2 4 3 4 4 4 5 8

let mut v = vec![0; 0];
let mut prev_capacity = std::usize::MAX;
for i in 0..1_000 {
let cap = v.capacity();
if cap != prev_capacity {
println!("{} {} {}", i, v.len(), cap);
prev_capacity = cap;
}
v.push(1);
}

This (probably) will print: 0 0 0 1 1 4 5 5 8 9 9 16 17 17 32 33 33 64 65 65 128 129 129 256 257 257 512 513 513 1024

13. Defining Closures

In this chapter, you will learn: • Why there is a need for anonymous inline functions, with type inference for the arguments and the return value type, without having to write braces, and which can access the variables that are alive at the function definition point • How such lightweight functions, named “closures”, can be declared and invoked

let factor = 2;
let multiply = |a| a * factor;
print!("{}", multiply(13));
let multiply_ref: &(Fn(i32) -> i32) = &multiply;
print!(
" {} {} {} {} {}",
(*multiply_ref)(13),
multiply_ref(13),
(|a| a * factor)(13),
(|a: i32| a * factor)(13),
|a| -> i32 { a * factor }(13));
// This will print: "26 26 26 26 26 26".
print!(
"{}",
(|v: &Vec<i32>| {
let mut sum = 0;
for i in 0..v.len() {
sum += v[i];
}
sum
})(&vec![11, 22, 34]));
//This will print "67" which is the sum of the numbers contained in the vector.

14. Using Changeable Strings

In this chapter, you will learn: • How static strings are implemented • How dynamic strings are implemented • How you can add characters to or remove characters from a dynamic string • How to convert a static string to a dynamic string, and conversely • How to concatenate strings

fn main(){
let mut a = "Hel";
print!("{}", a);
a = "lo";
print!("{}\n", a);
//This will print "Hello". 
use std::mem::*;
let a: &str = "";
let b: &str = "0123456789";
let c: &str = "abcdè";
print!("{} {} {}",
size_of_val(a),
size_of_val(b),
size_of_val(c));
//This program will print 0 10 6.
// use std::mem::*;
let a: &str = "";
let b: &str = "0123456789";
let c: &str = "abcdè";
print!("{} {} {}; ",
size_of_val(&a),
size_of_val(&b),
size_of_val(&c));
print!("{} {} {}\n",
size_of_val(&&a),
size_of_val(&&b),
size_of_val(&&c));
//This program in a 64-bit system will print "16 16 16; 8 8 8", while in a 32-bit system it will print "8 8 8; 4 4 4".
let mut a: String = "He".to_string();
a.push('l');
a.push('l');
a.push('o');
print!("{}\n", a);
//This will print "Hello".
let mut a: String = "Xy".to_string(); // "Xy"
a.remove(0); // "y"
a.insert(0, 'H'); // "Hy"
a.pop(); // "H"
a.push('i'); // "Hi"
print!("{}\n", a);
//This prints "Hi".
let mut s1 = "".to_string();
s1.push('e');
let mut s2 = "".to_string();
s2.push('è');
let mut s3 = "".to_string();
s3.push('€');
print!("{} {}; ", s1.capacity(), s1.len());
print!("{} {}; ", s2.capacity(), s2.len());
print!("{} {}\n", s3.capacity(), s3.len());
//This may print: "4 1; 2 2; 3 3".
let mut s = "".to_string();
for _ in 0..10 {
println!("{:?} {} {}",
s.as_ptr(), s.capacity(), s.len());
s.push('a');
}
println!("{:?} {} {}: {}\n",
s.as_ptr(), s.capacity(), s.len(), s);

}

//This, in a 64-bit system, may print:

0x1 0 0 0x7fbf95e20020 4 1 0x7fbf95e20020 4 2 0x7fbf95e20020 4 3 0x7fbf95e20020 4 4 0x7fbf95e20020 8 5 0x7fbf95e20020 8 6 0x7fbf95e20020 8 7 0x7fbf95e20020 8 8 0x7fbf95e2a000 16 9 0x7fbf95e2a000 16 10: aaaaaaaaaa

15. Ranges and Slices

In this chapter, you will learn: • How to use closed ranges, and open-ended ranges • How to process portions of arrays or vectors using slices

** continue ... mark p183**

Assessments

Continue

words

cascade
destruction
deallocated
Arithmetic
braces

评论区

写评论

还没有评论

1 共 0 条评论, 1 页