mirror of https://github.com/rust-lang/book
Compare commits
34 Commits
8602986ed9
...
1390c6c734
Author | SHA1 | Date |
---|---|---|
Pavel Roskin | 1390c6c734 | |
Carol (Nichols || Goulding) | cb0a24007f | |
Carol (Nichols || Goulding) | f954cb859f | |
Carol (Nichols || Goulding) | 98165c4279 | |
Chris Krycho | d207d894cc | |
Chris Krycho | 0b4e00345c | |
Chris Krycho | 502d012cab | |
Yuri Astrakhan | c13271897d | |
Chris Krycho | 8a79f3e15d | |
Chris Krycho | 62516ee9e3 | |
Chris Krycho | f3d9661aff | |
Chris Krycho | 54726034c5 | |
Chris Krycho | 8264d69aa6 | |
Yuri Astrakhan | c5211edeec | |
Chris Krycho | 0bcde15346 | |
Chris Krycho | 50149d92e0 | |
Chris Krycho | 874d9a2131 | |
Chris Krycho | 523d960984 | |
Chris Krycho | 0729f34edc | |
Chris Krycho | f9d4e058a9 | |
Chris Krycho | 82df41e8bd | |
Chris Krycho | 162d540045 | |
Chris Krycho | 6196a0ab45 | |
Chris Krycho | 96224742f3 | |
Chris Krycho | 1221096717 | |
Yuri Astrakhan | a786ec4a2b | |
Yuri Astrakhan | f55ac5d8fa | |
Pavel Roskin | 5190136589 | |
Amit Weisbord | 3a8ff9bdd2 | |
Amit Weisbord | 7b109240d2 | |
Víctor Hernández | 3ebc3b285f | |
Alex Gotsis | 6c63c46817 | |
JirCep | 15616bc09b | |
Sanjyoti | b260469985 |
|
@ -2,7 +2,7 @@
|
|||
name = "rust-book"
|
||||
version = "0.0.1"
|
||||
description = "The Rust Book"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "concat_chapters"
|
||||
|
|
|
@ -25,7 +25,7 @@ fn main() {
|
|||
// ANCHOR_END: expect
|
||||
|
||||
// ANCHOR: print_guess
|
||||
println!("You guessed: {guess}");
|
||||
println!("You guessed: {}", guess);
|
||||
// ANCHOR_END: print_guess
|
||||
}
|
||||
// ANCHOR: all
|
||||
|
|
|
@ -6,4 +6,4 @@ fn main() {
|
|||
// do stuff with s
|
||||
} // this scope is now over, and s is no longer valid
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,10 +14,10 @@ fn main() {
|
|||
// special happens.
|
||||
|
||||
fn takes_ownership(some_string: String) { // some_string comes into scope
|
||||
println!("{}", some_string);
|
||||
println!("{some_string}");
|
||||
} // Here, some_string goes out of scope and `drop` is called. The backing
|
||||
// memory is freed.
|
||||
|
||||
fn makes_copy(some_integer: i32) { // some_integer comes into scope
|
||||
println!("{}", some_integer);
|
||||
println!("{some_integer}");
|
||||
} // Here, some_integer goes out of scope. Nothing special happens.
|
||||
|
|
|
@ -3,7 +3,7 @@ fn main() {
|
|||
|
||||
let (s2, len) = calculate_length(s1);
|
||||
|
||||
println!("The length of '{}' is {}.", s2, len);
|
||||
println!("The length of '{s2}' is {len}.");
|
||||
}
|
||||
|
||||
fn calculate_length(s: String) -> (String, usize) {
|
||||
|
|
|
@ -4,6 +4,6 @@ fn main() {
|
|||
|
||||
s.push_str(", world!"); // push_str() appends a literal to a String
|
||||
|
||||
println!("{}", s); // This will print `hello, world!`
|
||||
// ANCHOR_END: here
|
||||
println!("{s}"); // This will print `hello, world!`
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -3,6 +3,6 @@ fn main() {
|
|||
let s1 = String::from("hello");
|
||||
let s2 = s1;
|
||||
|
||||
println!("{}, world!", s1);
|
||||
println!("{s1}, world!");
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -3,6 +3,6 @@ fn main() {
|
|||
let s1 = String::from("hello");
|
||||
let s2 = s1.clone();
|
||||
|
||||
println!("s1 = {}, s2 = {}", s1, s2);
|
||||
println!("s1 = {s1}, s2 = {s2}");
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -3,6 +3,6 @@ fn main() {
|
|||
let x = 5;
|
||||
let y = x;
|
||||
|
||||
println!("x = {}, y = {}", x, y);
|
||||
println!("x = {x}, y = {y}");
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ fn main() {
|
|||
let len = calculate_length(&s1);
|
||||
// ANCHOR_END: here
|
||||
|
||||
println!("The length of '{}' is {}.", s1, len);
|
||||
println!("The length of '{s1}' is {len}.");
|
||||
}
|
||||
|
||||
fn calculate_length(s: &String) -> usize {
|
||||
|
|
|
@ -3,7 +3,7 @@ fn main() {
|
|||
|
||||
let len = calculate_length(&s1);
|
||||
|
||||
println!("The length of '{}' is {}.", s1, len);
|
||||
println!("The length of '{s1}' is {len}.");
|
||||
}
|
||||
|
||||
// ANCHOR: here
|
||||
|
|
|
@ -4,10 +4,10 @@ fn main() {
|
|||
|
||||
let r1 = &s; // no problem
|
||||
let r2 = &s; // no problem
|
||||
println!("{} and {}", r1, r2);
|
||||
println!("{r1} and {r2}");
|
||||
// variables r1 and r2 will not be used after this point
|
||||
|
||||
let r3 = &mut s; // no problem
|
||||
println!("{}", r3);
|
||||
println!("{r3}");
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -18,6 +18,6 @@ fn main() {
|
|||
|
||||
s.clear(); // error!
|
||||
|
||||
println!("the first word is: {}", word);
|
||||
println!("the first word is: {word}");
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
|
|
|
@ -10,5 +10,5 @@ fn main() {
|
|||
height: 50,
|
||||
};
|
||||
|
||||
println!("rect1 is {:?}", rect1);
|
||||
println!("rect1 is {rect1:?}");
|
||||
}
|
||||
|
|
|
@ -10,5 +10,5 @@ fn main() {
|
|||
height: 50,
|
||||
};
|
||||
|
||||
println!("rect1 is {:#?}", rect1);
|
||||
println!("rect1 is {rect1:#?}");
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ fn main() {
|
|||
// ANCHOR: here
|
||||
let config_max = Some(3u8);
|
||||
match config_max {
|
||||
Some(max) => println!("The maximum is configured to be {}", max),
|
||||
Some(max) => println!("The maximum is configured to be {max}"),
|
||||
_ => (),
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
|
|
|
@ -19,7 +19,7 @@ fn value_in_cents(coin: Coin) -> u8 {
|
|||
Coin::Nickel => 5,
|
||||
Coin::Dime => 10,
|
||||
Coin::Quarter(state) => {
|
||||
println!("State quarter from {:?}!", state);
|
||||
println!("State quarter from {state:?}!");
|
||||
25
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ fn main() {
|
|||
// ANCHOR: here
|
||||
let config_max = Some(3u8);
|
||||
if let Some(max) = config_max {
|
||||
println!("The maximum is configured to be {}", max);
|
||||
println!("The maximum is configured to be {max}");
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ fn main() {
|
|||
// ANCHOR: here
|
||||
let mut count = 0;
|
||||
match coin {
|
||||
Coin::Quarter(state) => println!("State quarter from {:?}!", state),
|
||||
Coin::Quarter(state) => println!("State quarter from {state:?}!"),
|
||||
_ => count += 1,
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
|
|
|
@ -17,7 +17,7 @@ fn main() {
|
|||
// ANCHOR: here
|
||||
let mut count = 0;
|
||||
if let Coin::Quarter(state) = coin {
|
||||
println!("State quarter from {:?}!", state);
|
||||
println!("State quarter from {state:?}!");
|
||||
} else {
|
||||
count += 1;
|
||||
}
|
||||
|
|
|
@ -4,5 +4,5 @@ pub mod garden;
|
|||
|
||||
fn main() {
|
||||
let plant = Asparagus {};
|
||||
println!("I'm growing {:?}!", plant);
|
||||
println!("I'm growing {plant:?}!");
|
||||
}
|
||||
|
|
|
@ -7,6 +7,6 @@ fn main() {
|
|||
scores.insert(String::from("Blue"), 10);
|
||||
scores.insert(String::from("Blue"), 25);
|
||||
|
||||
println!("{:?}", scores);
|
||||
println!("{scores:?}");
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -8,6 +8,6 @@ fn main() {
|
|||
scores.entry(String::from("Yellow")).or_insert(50);
|
||||
scores.entry(String::from("Blue")).or_insert(50);
|
||||
|
||||
println!("{:?}", scores);
|
||||
println!("{scores:?}");
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -11,6 +11,6 @@ fn main() {
|
|||
*count += 1;
|
||||
}
|
||||
|
||||
println!("{:?}", map);
|
||||
println!("{map:?}");
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -5,6 +5,6 @@ fn main() {
|
|||
|
||||
let greeting_file = match greeting_file_result {
|
||||
Ok(file) => file,
|
||||
Err(error) => panic!("Problem opening the file: {:?}", error),
|
||||
Err(error) => panic!("Problem opening the file: {error:?}"),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -9,10 +9,10 @@ fn main() {
|
|||
Err(error) => match error.kind() {
|
||||
ErrorKind::NotFound => match File::create("hello.txt") {
|
||||
Ok(fc) => fc,
|
||||
Err(e) => panic!("Problem creating the file: {:?}", e),
|
||||
Err(e) => panic!("Problem creating the file: {e:?}"),
|
||||
},
|
||||
other_error => {
|
||||
panic!("Problem opening the file: {:?}", other_error);
|
||||
panic!("Problem opening the file: {other_error:?}");
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
println!("The largest number is {}", largest);
|
||||
println!("The largest number is {largest}");
|
||||
// ANCHOR_END: here
|
||||
assert_eq!(*largest, 100);
|
||||
// ANCHOR: here
|
||||
|
|
|
@ -9,7 +9,7 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
println!("The largest number is {}", largest);
|
||||
println!("The largest number is {largest}");
|
||||
|
||||
let number_list = vec![102, 34, 6000, 89, 54, 2, 43, 8];
|
||||
|
||||
|
@ -21,5 +21,5 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
println!("The largest number is {}", largest);
|
||||
println!("The largest number is {largest}");
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ fn main() {
|
|||
let number_list = vec![34, 50, 25, 100, 65];
|
||||
|
||||
let result = largest(&number_list);
|
||||
println!("The largest number is {}", result);
|
||||
println!("The largest number is {result}");
|
||||
// ANCHOR_END: here
|
||||
assert_eq!(*result, 100);
|
||||
// ANCHOR: here
|
||||
|
@ -23,7 +23,7 @@ fn main() {
|
|||
let number_list = vec![102, 34, 6000, 89, 54, 2, 43, 8];
|
||||
|
||||
let result = largest(&number_list);
|
||||
println!("The largest number is {}", result);
|
||||
println!("The largest number is {result}");
|
||||
// ANCHOR_END: here
|
||||
assert_eq!(*result, 6000);
|
||||
// ANCHOR: here
|
||||
|
|
|
@ -27,7 +27,7 @@ fn main() {
|
|||
let number_list = vec![34, 50, 25, 100, 65];
|
||||
|
||||
let result = largest_i32(&number_list);
|
||||
println!("The largest number is {}", result);
|
||||
println!("The largest number is {result}");
|
||||
// ANCHOR_END: here
|
||||
assert_eq!(*result, 100);
|
||||
// ANCHOR: here
|
||||
|
@ -35,7 +35,7 @@ fn main() {
|
|||
let char_list = vec!['y', 'm', 'a', 'q'];
|
||||
|
||||
let result = largest_char(&char_list);
|
||||
println!("The largest char is {}", result);
|
||||
println!("The largest char is {result}");
|
||||
// ANCHOR_END: here
|
||||
assert_eq!(*result, 'y');
|
||||
// ANCHOR: here
|
||||
|
|
|
@ -14,10 +14,10 @@ fn main() {
|
|||
let number_list = vec![34, 50, 25, 100, 65];
|
||||
|
||||
let result = largest(&number_list);
|
||||
println!("The largest number is {}", result);
|
||||
println!("The largest number is {result}");
|
||||
|
||||
let char_list = vec!['y', 'm', 'a', 'q'];
|
||||
|
||||
let result = largest(&char_list);
|
||||
println!("The largest char is {}", result);
|
||||
println!("The largest char is {result}");
|
||||
}
|
||||
|
|
|
@ -6,5 +6,5 @@ fn main() {
|
|||
r = &x;
|
||||
}
|
||||
|
||||
println!("r: {}", r);
|
||||
println!("r: {r}");
|
||||
}
|
||||
|
|
|
@ -6,5 +6,5 @@ fn main() {
|
|||
r = &x; // | |
|
||||
} // -+ |
|
||||
// |
|
||||
println!("r: {}", r); // |
|
||||
println!("r: {r}"); // |
|
||||
} // ---------+
|
||||
|
|
|
@ -3,6 +3,6 @@ fn main() {
|
|||
// |
|
||||
let r = &x; // --+-- 'a |
|
||||
// | |
|
||||
println!("r: {}", r); // | |
|
||||
println!("r: {r}"); // | |
|
||||
// --+ |
|
||||
} // ----------+
|
||||
|
|
|
@ -3,5 +3,5 @@ fn main() {
|
|||
let string2 = "xyz";
|
||||
|
||||
let result = longest(string1.as_str(), string2);
|
||||
println!("The longest string is {}", result);
|
||||
println!("The longest string is {result}");
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ fn main() {
|
|||
let string2 = "xyz";
|
||||
|
||||
let result = longest(string1.as_str(), string2);
|
||||
println!("The longest string is {}", result);
|
||||
println!("The longest string is {result}");
|
||||
}
|
||||
|
||||
// ANCHOR: here
|
||||
|
|
|
@ -3,7 +3,7 @@ fn main() {
|
|||
let string2 = "xyz";
|
||||
|
||||
let result = longest(string1.as_str(), string2);
|
||||
println!("The longest string is {}", result);
|
||||
println!("The longest string is {result}");
|
||||
}
|
||||
|
||||
// ANCHOR: here
|
||||
|
|
|
@ -5,7 +5,7 @@ fn main() {
|
|||
{
|
||||
let string2 = String::from("xyz");
|
||||
let result = longest(string1.as_str(), string2.as_str());
|
||||
println!("The longest string is {}", result);
|
||||
println!("The longest string is {result}");
|
||||
}
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
|
|
|
@ -9,8 +9,8 @@ error[E0597]: `string2` does not live long enough
|
|||
| ^^^^^^^ borrowed value does not live long enough
|
||||
7 | }
|
||||
| - `string2` dropped here while still borrowed
|
||||
8 | println!("The longest string is {}", result);
|
||||
| ------ borrow later used here
|
||||
8 | println!("The longest string is {result}");
|
||||
| ------ borrow later used here
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
||||
error: could not compile `chapter10` (bin "chapter10") due to 1 previous error
|
||||
|
|
|
@ -6,7 +6,7 @@ fn main() {
|
|||
let string2 = String::from("xyz");
|
||||
result = longest(string1.as_str(), string2.as_str());
|
||||
}
|
||||
println!("The longest string is {}", result);
|
||||
println!("The longest string is {result}");
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ fn main() {
|
|||
let string2 = "efghijklmnopqrstuvwxyz";
|
||||
|
||||
let result = longest(string1.as_str(), string2);
|
||||
println!("The longest string is {}", result);
|
||||
println!("The longest string is {result}");
|
||||
}
|
||||
|
||||
// ANCHOR: here
|
||||
|
|
|
@ -3,7 +3,7 @@ fn main() {
|
|||
let string2 = "xyz";
|
||||
|
||||
let result = longest(string1.as_str(), string2);
|
||||
println!("The longest string is {}", result);
|
||||
println!("The longest string is {result}");
|
||||
}
|
||||
|
||||
// ANCHOR: here
|
||||
|
|
|
@ -13,7 +13,7 @@ impl<'a> ImportantExcerpt<'a> {
|
|||
// ANCHOR: 3rd
|
||||
impl<'a> ImportantExcerpt<'a> {
|
||||
fn announce_and_return_part(&self, announcement: &str) -> &str {
|
||||
println!("Attention please: {}", announcement);
|
||||
println!("Attention please: {announcement}");
|
||||
self.part
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ fn main() {
|
|||
string2,
|
||||
"Today is someone's birthday!",
|
||||
);
|
||||
println!("The longest string is {}", result);
|
||||
println!("The longest string is {result}");
|
||||
}
|
||||
|
||||
// ANCHOR: here
|
||||
|
@ -21,7 +21,7 @@ fn longest_with_an_announcement<'a, T>(
|
|||
where
|
||||
T: Display,
|
||||
{
|
||||
println!("Announcement! {}", ann);
|
||||
println!("Announcement! {ann}");
|
||||
if x.len() > y.len() {
|
||||
x
|
||||
} else {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
fn prints_and_returns_10(a: i32) -> i32 {
|
||||
println!("I got the value {}", a);
|
||||
println!("I got the value {a}");
|
||||
10
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
pub fn greeting(name: &str) -> String {
|
||||
format!("Hello {}!", name)
|
||||
format!("Hello {name}!")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
pub fn prints_and_returns_10(a: i32) -> i32 {
|
||||
println!("I got the value {}", a);
|
||||
println!("I got the value {a}");
|
||||
10
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,6 @@ fn main() {
|
|||
let query = &args[1];
|
||||
let file_path = &args[2];
|
||||
|
||||
println!("Searching for {}", query);
|
||||
println!("In file {}", file_path);
|
||||
println!("Searching for {query}");
|
||||
println!("In file {file_path}");
|
||||
}
|
||||
|
|
|
@ -6,6 +6,6 @@ fn main() {
|
|||
let query = &args[1];
|
||||
let file_path = &args[2];
|
||||
|
||||
println!("Searching for {}", query);
|
||||
println!("In file {}", file_path);
|
||||
println!("Searching for {query}");
|
||||
println!("In file {file_path}");
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@ fn main() {
|
|||
let query = &args[1];
|
||||
let file_path = &args[2];
|
||||
|
||||
println!("Searching for {}", query);
|
||||
println!("Searching for {query}");
|
||||
// ANCHOR: here
|
||||
println!("In file {}", file_path);
|
||||
println!("In file {file_path}");
|
||||
|
||||
let contents = fs::read_to_string(file_path)
|
||||
.expect("Should have been able to read the file");
|
||||
|
|
|
@ -10,8 +10,8 @@ fn main() {
|
|||
// --snip--
|
||||
// ANCHOR_END: here
|
||||
|
||||
println!("Searching for {}", query);
|
||||
println!("In file {}", file_path);
|
||||
println!("Searching for {query}");
|
||||
println!("In file {file_path}");
|
||||
|
||||
let contents = fs::read_to_string(file_path)
|
||||
.expect("Should have been able to read the file");
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
fn main() {
|
||||
let list = vec![1, 2, 3];
|
||||
println!("Before defining closure: {:?}", list);
|
||||
println!("Before defining closure: {list:?}");
|
||||
|
||||
let only_borrows = || println!("From closure: {:?}", list);
|
||||
let only_borrows = || println!("From closure: {list:?}");
|
||||
|
||||
println!("Before calling closure: {:?}", list);
|
||||
println!("Before calling closure: {list:?}");
|
||||
only_borrows();
|
||||
println!("After calling closure: {:?}", list);
|
||||
println!("After calling closure: {list:?}");
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
fn main() {
|
||||
let mut list = vec![1, 2, 3];
|
||||
println!("Before defining closure: {:?}", list);
|
||||
println!("Before defining closure: {list:?}");
|
||||
|
||||
let mut borrows_mutably = || list.push(7);
|
||||
|
||||
borrows_mutably();
|
||||
println!("After calling closure: {:?}", list);
|
||||
println!("After calling closure: {list:?}");
|
||||
}
|
||||
|
|
|
@ -2,9 +2,9 @@ use std::thread;
|
|||
|
||||
fn main() {
|
||||
let list = vec![1, 2, 3];
|
||||
println!("Before defining closure: {:?}", list);
|
||||
println!("Before defining closure: {list:?}");
|
||||
|
||||
thread::spawn(move || println!("From thread: {:?}", list))
|
||||
thread::spawn(move || println!("From thread: {list:?}"))
|
||||
.join()
|
||||
.unwrap();
|
||||
}
|
||||
|
|
|
@ -12,5 +12,5 @@ fn main() {
|
|||
];
|
||||
|
||||
list.sort_by_key(|r| r.width);
|
||||
println!("{:#?}", list);
|
||||
println!("{list:#?}");
|
||||
}
|
||||
|
|
|
@ -18,5 +18,5 @@ fn main() {
|
|||
sort_operations.push(value);
|
||||
r.width
|
||||
});
|
||||
println!("{:#?}", list);
|
||||
println!("{list:#?}");
|
||||
}
|
||||
|
|
|
@ -16,5 +16,5 @@ fn main() {
|
|||
num_sort_operations += 1;
|
||||
r.width
|
||||
});
|
||||
println!("{:#?}, sorted in {num_sort_operations} operations", list);
|
||||
println!("{list:#?}, sorted in {num_sort_operations} operations");
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ fn main() {
|
|||
let v1_iter = v1.iter();
|
||||
|
||||
for val in v1_iter {
|
||||
println!("Got: {}", val);
|
||||
println!("Got: {val}");
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
fn main() {
|
||||
let b = Box::new(5);
|
||||
println!("b = {}", b);
|
||||
println!("b = {b}");
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ fn main() {
|
|||
|
||||
*value.borrow_mut() += 10;
|
||||
|
||||
println!("a after = {:?}", a);
|
||||
println!("b after = {:?}", b);
|
||||
println!("c after = {:?}", c);
|
||||
println!("a after = {a:?}");
|
||||
println!("b after = {b:?}");
|
||||
println!("c after = {c:?}");
|
||||
}
|
||||
|
|
|
@ -4,13 +4,13 @@ use std::time::Duration;
|
|||
fn main() {
|
||||
thread::spawn(|| {
|
||||
for i in 1..10 {
|
||||
println!("hi number {} from the spawned thread!", i);
|
||||
println!("hi number {i} from the spawned thread!");
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
}
|
||||
});
|
||||
|
||||
for i in 1..5 {
|
||||
println!("hi number {} from the main thread!", i);
|
||||
println!("hi number {i} from the main thread!");
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,13 @@ use std::time::Duration;
|
|||
fn main() {
|
||||
let handle = thread::spawn(|| {
|
||||
for i in 1..10 {
|
||||
println!("hi number {} from the spawned thread!", i);
|
||||
println!("hi number {i} from the spawned thread!");
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
}
|
||||
});
|
||||
|
||||
for i in 1..5 {
|
||||
println!("hi number {} from the main thread!", i);
|
||||
println!("hi number {i} from the main thread!");
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
}
|
||||
|
||||
|
|
|
@ -5,15 +5,15 @@ error[E0373]: closure may outlive the current function, but it borrows `v`, whic
|
|||
|
|
||||
6 | let handle = thread::spawn(|| {
|
||||
| ^^ may outlive borrowed value `v`
|
||||
7 | println!("Here's a vector: {:?}", v);
|
||||
| - `v` is borrowed here
|
||||
7 | println!("Here's a vector: {v:?}");
|
||||
| - `v` is borrowed here
|
||||
|
|
||||
note: function requires argument type to outlive `'static`
|
||||
--> src/main.rs:6:18
|
||||
|
|
||||
6 | let handle = thread::spawn(|| {
|
||||
| __________________^
|
||||
7 | | println!("Here's a vector: {:?}", v);
|
||||
7 | | println!("Here's a vector: {v:?}");
|
||||
8 | | });
|
||||
| |______^
|
||||
help: to force the closure to take ownership of `v` (and any other referenced variables), use the `move` keyword
|
||||
|
|
|
@ -4,7 +4,7 @@ fn main() {
|
|||
let v = vec![1, 2, 3];
|
||||
|
||||
let handle = thread::spawn(|| {
|
||||
println!("Here's a vector: {:?}", v);
|
||||
println!("Here's a vector: {v:?}");
|
||||
});
|
||||
|
||||
handle.join().unwrap();
|
||||
|
|
|
@ -4,7 +4,7 @@ fn main() {
|
|||
let v = vec![1, 2, 3];
|
||||
|
||||
let handle = thread::spawn(|| {
|
||||
println!("Here's a vector: {:?}", v);
|
||||
println!("Here's a vector: {v:?}");
|
||||
});
|
||||
|
||||
drop(v); // oh no!
|
||||
|
|
|
@ -4,7 +4,7 @@ fn main() {
|
|||
let v = vec![1, 2, 3];
|
||||
|
||||
let handle = thread::spawn(move || {
|
||||
println!("Here's a vector: {:?}", v);
|
||||
println!("Here's a vector: {v:?}");
|
||||
});
|
||||
|
||||
handle.join().unwrap();
|
||||
|
|
|
@ -10,5 +10,5 @@ fn main() {
|
|||
});
|
||||
|
||||
let received = rx.recv().unwrap();
|
||||
println!("Got: {}", received);
|
||||
println!("Got: {received}");
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ error[E0382]: borrow of moved value: `val`
|
|||
| --- move occurs because `val` has type `String`, which does not implement the `Copy` trait
|
||||
9 | tx.send(val).unwrap();
|
||||
| --- value moved here
|
||||
10 | println!("val is {}", val);
|
||||
| ^^^ value borrowed here after move
|
||||
10 | println!("val is {val}");
|
||||
| ^^^ value borrowed here after move
|
||||
|
|
||||
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: consider cloning the value if the performance cost is acceptable
|
||||
|
|
|
@ -7,9 +7,9 @@ fn main() {
|
|||
thread::spawn(move || {
|
||||
let val = String::from("hi");
|
||||
tx.send(val).unwrap();
|
||||
println!("val is {}", val);
|
||||
println!("val is {val}");
|
||||
});
|
||||
|
||||
let received = rx.recv().unwrap();
|
||||
println!("Got: {}", received);
|
||||
println!("Got: {received}");
|
||||
}
|
||||
|
|
|
@ -20,6 +20,6 @@ fn main() {
|
|||
});
|
||||
|
||||
for received in rx {
|
||||
println!("Got: {}", received);
|
||||
println!("Got: {received}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ fn main() {
|
|||
});
|
||||
|
||||
for received in rx {
|
||||
println!("Got: {}", received);
|
||||
println!("Got: {received}");
|
||||
}
|
||||
|
||||
// --snip--
|
||||
|
|
|
@ -8,5 +8,5 @@ fn main() {
|
|||
*num = 6;
|
||||
}
|
||||
|
||||
println!("m = {:?}", m);
|
||||
println!("m = {m:?}");
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::time::Duration;
|
|||
fn main() {
|
||||
let handle = thread::spawn(|| {
|
||||
for i in 1..10 {
|
||||
println!("hi number {} from the spawned thread!", i);
|
||||
println!("hi number {i} from the spawned thread!");
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
}
|
||||
});
|
||||
|
@ -12,7 +12,7 @@ fn main() {
|
|||
handle.join().unwrap();
|
||||
|
||||
for i in 1..5 {
|
||||
println!("hi number {} from the main thread!", i);
|
||||
println!("hi number {i} from the main thread!");
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@ error[E0382]: use of moved value: `v`
|
|||
5 |
|
||||
6 | let handle = thread::spawn(move || {
|
||||
| ------- value moved into closure here
|
||||
7 | println!("Here's a vector: {:?}", v);
|
||||
| - variable moved due to use in closure
|
||||
7 | println!("Here's a vector: {v:?}");
|
||||
| - variable moved due to use in closure
|
||||
...
|
||||
10 | drop(v); // oh no!
|
||||
| ^ value used here after move
|
||||
|
|
|
@ -4,7 +4,7 @@ fn main() {
|
|||
let v = vec![1, 2, 3];
|
||||
|
||||
let handle = thread::spawn(move || {
|
||||
println!("Here's a vector: {:?}", v);
|
||||
println!("Here's a vector: {v:?}");
|
||||
});
|
||||
|
||||
drop(v); // oh no!
|
||||
|
|
|
@ -7,7 +7,7 @@ fn main() {
|
|||
stack.push(3);
|
||||
|
||||
while let Some(top) = stack.pop() {
|
||||
println!("{}", top);
|
||||
println!("{top}");
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ fn main() {
|
|||
let v = vec!['a', 'b', 'c'];
|
||||
|
||||
for (index, value) in v.iter().enumerate() {
|
||||
println!("{} is at index {}", value, index);
|
||||
println!("{value} is at index {index}");
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
fn print_coordinates(&(x, y): &(i32, i32)) {
|
||||
println!("Current location: ({}, {})", x, y);
|
||||
println!("Current location: ({x}, {y})");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -2,7 +2,7 @@ fn main() {
|
|||
let some_option_value: Option<i32> = None;
|
||||
// ANCHOR: here
|
||||
if let Some(x) = some_option_value {
|
||||
println!("{}", x);
|
||||
println!("{x}");
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
fn main() {
|
||||
// ANCHOR: here
|
||||
if let x = 5 {
|
||||
println!("{}", x);
|
||||
println!("{x}");
|
||||
};
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ fn main() {
|
|||
match x {
|
||||
Some(50) => println!("Got 50"),
|
||||
Some(y) => println!("Matched, y = {y}"),
|
||||
_ => println!("Default case, x = {:?}", x),
|
||||
_ => println!("Default case, x = {x:?}"),
|
||||
}
|
||||
|
||||
println!("at the end: x = {:?}, y = {y}", x);
|
||||
println!("at the end: x = {x:?}, y = {y}");
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ fn main() {
|
|||
println!("Text message: {text}");
|
||||
}
|
||||
Message::ChangeColor(r, g, b) => {
|
||||
println!("Change the color to red {r}, green {g}, and blue {b}",)
|
||||
println!("Change the color to red {r}, green {g}, and blue {b}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
fn foo(_: i32, y: i32) {
|
||||
println!("This code only uses the y parameter: {}", y);
|
||||
println!("This code only uses the y parameter: {y}");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -12,6 +12,6 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
println!("setting is {:?}", setting_value);
|
||||
println!("setting is {setting_value:?}");
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -6,6 +6,6 @@ fn main() {
|
|||
println!("found a string");
|
||||
}
|
||||
|
||||
println!("{:?}", s);
|
||||
println!("{s:?}");
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -6,6 +6,6 @@ fn main() {
|
|||
println!("found a string");
|
||||
}
|
||||
|
||||
println!("{:?}", s);
|
||||
println!("{s:?}");
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ fn main() {
|
|||
let origin = Point { x: 0, y: 0, z: 0 };
|
||||
|
||||
match origin {
|
||||
Point { x, .. } => println!("x is {}", x),
|
||||
Point { x, .. } => println!("x is {x}"),
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ fn main() {
|
|||
|
||||
match numbers {
|
||||
(.., second, ..) => {
|
||||
println!("Some numbers: {}", second)
|
||||
println!("Some numbers: {second}")
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ fn main() {
|
|||
let num = Some(4);
|
||||
|
||||
match num {
|
||||
Some(x) if x % 2 == 0 => println!("The number {} is even", x),
|
||||
Some(x) => println!("The number {} is odd", x),
|
||||
Some(x) if x % 2 == 0 => println!("The number {x} is even"),
|
||||
Some(x) => println!("The number {x} is odd"),
|
||||
None => (),
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
|
|
|
@ -5,8 +5,8 @@ fn main() {
|
|||
match x {
|
||||
Some(50) => println!("Got 50"),
|
||||
Some(n) if n == y => println!("Matched, n = {n}"),
|
||||
_ => println!("Default case, x = {:?}", x),
|
||||
_ => println!("Default case, x = {x:?}"),
|
||||
}
|
||||
|
||||
println!("at the end: x = {:?}, y = {y}", x);
|
||||
println!("at the end: x = {x:?}, y = {y}");
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@ fn main() {
|
|||
match msg {
|
||||
Message::Hello {
|
||||
id: id_variable @ 3..=7,
|
||||
} => println!("Found an id in range: {}", id_variable),
|
||||
} => println!("Found an id in range: {id_variable}"),
|
||||
Message::Hello { id: 10..=12 } => {
|
||||
println!("Found an id in another range")
|
||||
}
|
||||
Message::Hello { id } => println!("Found some other id: {}", id),
|
||||
Message::Hello { id } => println!("Found some other id: {id}"),
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
static HELLO_WORLD: &str = "Hello, world!";
|
||||
|
||||
fn main() {
|
||||
println!("name is: {}", HELLO_WORLD);
|
||||
println!("name is: {HELLO_WORLD}");
|
||||
}
|
||||
|
|
|
@ -10,6 +10,6 @@ fn main() {
|
|||
add_to_count(3);
|
||||
|
||||
unsafe {
|
||||
println!("COUNTER: {}", COUNTER);
|
||||
println!("COUNTER: {COUNTER}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ trait OutlinePrint: fmt::Display {
|
|||
let len = output.len();
|
||||
println!("{}", "*".repeat(len + 4));
|
||||
println!("*{}*", " ".repeat(len + 2));
|
||||
println!("* {} *", output);
|
||||
println!("* {output} *");
|
||||
println!("*{}*", " ".repeat(len + 2));
|
||||
println!("{}", "*".repeat(len + 4));
|
||||
}
|
||||
|
|
|
@ -10,5 +10,5 @@ impl fmt::Display for Wrapper {
|
|||
|
||||
fn main() {
|
||||
let w = Wrapper(vec![String::from("hello"), String::from("world")]);
|
||||
println!("w = {}", w);
|
||||
println!("w = {w}");
|
||||
}
|
||||
|
|
|
@ -9,5 +9,5 @@ fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
|
|||
fn main() {
|
||||
let answer = do_twice(add_one, 5);
|
||||
|
||||
println!("The answer is: {}", answer);
|
||||
println!("The answer is: {answer}");
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ trait OutlinePrint: fmt::Display {
|
|||
let len = output.len();
|
||||
println!("{}", "*".repeat(len + 4));
|
||||
println!("*{}*", " ".repeat(len + 2));
|
||||
println!("* {} *", output);
|
||||
println!("* {output} *");
|
||||
println!("*{}*", " ".repeat(len + 2));
|
||||
println!("{}", "*".repeat(len + 4));
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ trait OutlinePrint: fmt::Display {
|
|||
let len = output.len();
|
||||
println!("{}", "*".repeat(len + 4));
|
||||
println!("*{}*", " ".repeat(len + 2));
|
||||
println!("* {} *", output);
|
||||
println!("* {output} *");
|
||||
println!("*{}*", " ".repeat(len + 2));
|
||||
println!("{}", "*".repeat(len + 4));
|
||||
}
|
||||
|
|
|
@ -21,5 +21,5 @@ fn handle_connection(mut stream: TcpStream) {
|
|||
.take_while(|line| !line.is_empty())
|
||||
.collect();
|
||||
|
||||
println!("Request: {:#?}", http_request);
|
||||
println!("Request: {http_request:#?}");
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ optionally one library crate. As a package grows, you can extract parts into
|
|||
separate crates that become external dependencies. This chapter covers all
|
||||
these techniques. For very large projects comprising a set of interrelated
|
||||
packages that evolve together, Cargo provides *workspaces*, which we’ll cover
|
||||
in “Cargo Workspaces” on page XX.
|
||||
in the “Cargo Workspaces” section in Chapter 14.
|
||||
|
||||
We’ll also discuss encapsulating implementation details, which lets you reuse
|
||||
code at a higher level: once you’ve implemented an operation, other code can
|
||||
|
@ -43,11 +43,11 @@ organization, including which details are exposed, which details are private,
|
|||
and what names are in each scope in your programs. These features, sometimes
|
||||
collectively referred to as the *module system*, include:
|
||||
|
||||
* **Packages **: A Cargo feature that lets you build, test, and share crates
|
||||
* **Crates**: A tree of modules that produces a library or executable
|
||||
* **Modules and use**: Let you control the organization, scope, and privacy of
|
||||
paths
|
||||
* **Paths **: A way of naming an item, such as a struct, function, or module
|
||||
* **Packages:** A Cargo feature that lets you build, test, and share crates
|
||||
* **Crates:** A tree of modules that produces a library or executable
|
||||
* **Modules** and **use:** Let you control the organization, scope, and
|
||||
privacy of paths
|
||||
* **Paths:** A way of naming an item, such as a struct, function, or module
|
||||
|
||||
In this chapter, we’ll cover all these features, discuss how they interact, and
|
||||
explain how to use them to manage scope. By the end, you should have a solid
|
||||
|
@ -59,35 +59,36 @@ The first parts of the module system we’ll cover are packages and crates.
|
|||
|
||||
A *crate* is the smallest amount of code that the Rust compiler considers at a
|
||||
time. Even if you run `rustc` rather than `cargo` and pass a single source code
|
||||
file (as we did all the way back in “Writing and Running a Rust Program” on
|
||||
page XX), the compiler considers that file to be a crate. Crates can contain
|
||||
modules, and the modules may be defined in other files that get compiled with
|
||||
the crate, as we’ll see in the coming sections.
|
||||
file (as we did all the way back in the “Writing and Running a Rust Program”
|
||||
section of Chapter 1), the compiler considers that file to be a crate. Crates
|
||||
can contain modules, and the modules may be defined in other files that get
|
||||
compiled with the crate, as we’ll see in the coming sections.
|
||||
|
||||
A crate can come in one of two forms: a binary crate or a library crate.
|
||||
*Binary crates* are programs you can compile to an executable that you can run,
|
||||
such as a command line program or a server. Each must have a function called
|
||||
such as a command-line program or a server. Each must have a function called
|
||||
`main` that defines what happens when the executable runs. All the crates we’ve
|
||||
created so far have been binary crates.
|
||||
|
||||
*Library crates* don’t have a `main` function, and they don’t compile to an
|
||||
executable. Instead, they define functionality intended to be shared with
|
||||
multiple projects. For example, the `rand` crate we used in Chapter 2 provides
|
||||
functionality that generates random numbers. Most of the time when Rustaceans
|
||||
say “crate,” they mean library crate, and they use “crate” interchangeably with
|
||||
the general programming concept of a “library.”
|
||||
multiple projects. For example, the `rand` crate we used in Chapter
|
||||
2 provides functionality that generates random numbers.
|
||||
Most of the time when Rustaceans say “crate”, they mean library crate, and they
|
||||
use “crate” interchangeably with the general programming concept of a “library".
|
||||
|
||||
The *crate root* is a source file that the Rust compiler starts from and makes
|
||||
up the root module of your crate (we’ll explain modules in depth in “Defining
|
||||
Modules to Control Scope and Privacy” on page XX).
|
||||
up the root module of your crate (we’ll explain modules in depth in the
|
||||
“Defining Modules to Control Scope and Privacy”
|
||||
section).
|
||||
|
||||
A *package* is a bundle of one or more crates that provides a set of
|
||||
functionality. A package contains a *Cargo.toml* file that describes how to
|
||||
build those crates. Cargo is actually a package that contains the binary crate
|
||||
for the command line tool you’ve been using to build your code. The Cargo
|
||||
for the command-line tool you’ve been using to build your code. The Cargo
|
||||
package also contains a library crate that the binary crate depends on. Other
|
||||
projects can depend on the Cargo library crate to use the same logic the Cargo
|
||||
command line tool uses.
|
||||
command-line tool uses.
|
||||
|
||||
A crate can come in one of two forms: a binary crate or a library crate. A
|
||||
package can contain as many binary crates as you like, but at most only one
|
||||
|
@ -123,94 +124,6 @@ and *src/lib.rs*, it has two crates: a binary and a library, both with the same
|
|||
name as the package. A package can have multiple binary crates by placing files
|
||||
in the *src/bin* directory: each file will be a separate binary crate.
|
||||
|
||||
> ### Modules Cheat Sheet
|
||||
>
|
||||
> Before we get to the details of modules and paths, here we provide a quick
|
||||
reference on how modules, paths, the `use` keyword, and the `pub` keyword work
|
||||
in the compiler, and how most developers organize their code. We’ll be going
|
||||
through examples of each of these rules throughout this chapter, but this is a
|
||||
great place to refer to as a reminder of how modules work.
|
||||
>
|
||||
> * **Start from the crate root**: When compiling a crate, the compiler first
|
||||
looks in the crate root file (usually *src/lib.rs* for a library crate or
|
||||
*src/main.rs* for a binary crate) for code to compile.
|
||||
> * **Declaring modules**: In the crate root file, you can declare new modules;
|
||||
say you declare a “garden” module with `mod garden;`. The compiler will look
|
||||
for the module’s code in these places:
|
||||
>
|
||||
> * Inline, within curly brackets that replace the semicolon following `mod
|
||||
garden`
|
||||
> * In the file *src/garden.rs.*
|
||||
> * In the file *src/garden/mod.rs*
|
||||
> * **Declaring submodules**: In any file other than the crate root, you can
|
||||
declare submodules. For example, you might declare `mod vegetables;` in
|
||||
*src/garden.rs*. The compiler will look for the submodule’s code within the
|
||||
directory named for the parent module in these places:
|
||||
>
|
||||
> * Inline, directly following `mod vegetables`, within curly brackets instead
|
||||
of the semicolon
|
||||
> * In the file *src/garden/vegetables.rs*
|
||||
> * In the file *src/garden/vegetables/mod.rs*
|
||||
> * **Paths to code in modules**: Once a module is part of your crate, you can
|
||||
refer to code in that module from anywhere else in that same crate, as long as
|
||||
the privacy rules allow, using the path to the code. For example, an
|
||||
`Asparagus` type in the garden vegetables module would be found at
|
||||
`crate::garden::vegetables::Asparagus`.
|
||||
> * **Private vs. public**: Code within a module is private from its parent
|
||||
modules by default. To make a module public, declare it with `pub mod` instead
|
||||
of `mod`. To make items within a public module public as well, use `pub` before
|
||||
their declarations.
|
||||
> * **The use keyword**: Within a scope, the `use` keyword creates shortcuts to
|
||||
items to reduce repetition of long paths. In any scope that can refer to
|
||||
`crate::garden::vegetables::Asparagus`, you can create a shortcut with `use
|
||||
crate::garden::vegetables::Asparagus;` and from then on you only need to write
|
||||
`Asparagus` to make use of that type in the scope.
|
||||
>
|
||||
> Here, we create a binary crate named `backyard` that illustrates these rules.
|
||||
The crate’s directory, also named `backyard`, contains these files and
|
||||
directories:
|
||||
>
|
||||
> ```
|
||||
> backyard
|
||||
> ├── Cargo.lock
|
||||
> ├── Cargo.toml
|
||||
> └── src
|
||||
> ├── garden
|
||||
> │ └── vegetables.rs
|
||||
> ├── garden.rs
|
||||
> └── main.rs
|
||||
> ```
|
||||
>
|
||||
> The crate root file in this case is *src/main.rs*, and it contains:
|
||||
>
|
||||
> ```
|
||||
> use crate::garden::vegetables::Asparagus;
|
||||
>
|
||||
> pub mod garden;
|
||||
>
|
||||
> fn main() {
|
||||
> let plant = Asparagus {};
|
||||
> println!("I'm growing {:?}!", plant);
|
||||
> }
|
||||
> ```
|
||||
>
|
||||
> The `pub mod garden;` line tells the compiler to include the code it finds in
|
||||
*src/garden.rs*, which is:
|
||||
>
|
||||
> ```
|
||||
> pub mod vegetables;
|
||||
> ```
|
||||
>
|
||||
> Here, `pub mod vegetables;` means the code in *src/garden/vegetables.rs* is
|
||||
included too. That code is:
|
||||
>
|
||||
> ```
|
||||
> #[derive(Debug)]
|
||||
> pub struct Asparagus {}
|
||||
> ```
|
||||
>
|
||||
> Now let’s get into the details of these rules and demonstrate them in action!
|
||||
|
||||
## Defining Modules to Control Scope and Privacy
|
||||
|
||||
In this section, we’ll talk about modules and other parts of the module system,
|
||||
|
@ -218,6 +131,98 @@ namely *paths*, which allow you to name items; the `use` keyword that brings a
|
|||
path into scope; and the `pub` keyword to make items public. We’ll also discuss
|
||||
the `as` keyword, external packages, and the glob operator.
|
||||
|
||||
### Modules Cheat Sheet
|
||||
|
||||
Before we get to the details of modules and paths, here we provide a quick
|
||||
reference on how modules, paths, the `use` keyword, and the `pub` keyword work
|
||||
in the compiler, and how most developers organize their code. We’ll be going
|
||||
through examples of each of these rules throughout this chapter, but this is a
|
||||
great place to refer to as a reminder of how modules work.
|
||||
|
||||
- **Start from the crate root**: When compiling a crate, the compiler first
|
||||
looks in the crate root file (usually *src/lib.rs* for a library crate or
|
||||
*src/main.rs* for a binary crate) for code to compile.
|
||||
- **Declaring modules**: In the crate root file, you can declare new modules;
|
||||
say you declare a “garden” module with `mod garden;`. The compiler will look
|
||||
for the module’s code in these places:
|
||||
- Inline, within curly brackets that replace the semicolon following `mod
|
||||
garden`
|
||||
- In the file *src/garden.rs*
|
||||
- In the file *src/garden/mod.rs*
|
||||
- **Declaring submodules**: In any file other than the crate root, you can
|
||||
declare submodules. For example, you might declare `mod vegetables;` in
|
||||
*src/garden.rs*. The compiler will look for the submodule’s code within the
|
||||
directory named for the parent module in these places:
|
||||
- Inline, directly following `mod vegetables`, within curly brackets instead
|
||||
of the semicolon
|
||||
- In the file *src/garden/vegetables.rs*
|
||||
- In the file *src/garden/vegetables/mod.rs*
|
||||
- **Paths to code in modules**: Once a module is part of your crate, you can
|
||||
refer to code in that module from anywhere else in that same crate, as long
|
||||
as the privacy rules allow, using the path to the code. For example, an
|
||||
`Asparagus` type in the garden vegetables module would be found at
|
||||
`crate::garden::vegetables::Asparagus`.
|
||||
- **Private vs. public**: Code within a module is private from its parent
|
||||
modules by default. To make a module public, declare it with `pub mod`
|
||||
instead of `mod`. To make items within a public module public as well, use
|
||||
`pub` before their declarations.
|
||||
- **The `use` keyword**: Within a scope, the `use` keyword creates shortcuts to
|
||||
items to reduce repetition of long paths. In any scope that can refer to
|
||||
`crate::garden::vegetables::Asparagus`, you can create a shortcut with `use
|
||||
crate::garden::vegetables::Asparagus;` and from then on you only need to
|
||||
write `Asparagus` to make use of that type in the scope.
|
||||
|
||||
Here, we create a binary crate named `backyard` that illustrates these rules.
|
||||
The crate’s directory, also named `backyard`, contains these files and
|
||||
directories:
|
||||
|
||||
```
|
||||
backyard
|
||||
├── Cargo.lock
|
||||
├── Cargo.toml
|
||||
└── src
|
||||
├── garden
|
||||
│ └── vegetables.rs
|
||||
├── garden.rs
|
||||
└── main.rs
|
||||
```
|
||||
|
||||
The crate root file in this case is *src/main.rs*, and it contains:
|
||||
|
||||
Filename: src/main.rs
|
||||
|
||||
```
|
||||
use crate::garden::vegetables::Asparagus;
|
||||
|
||||
pub mod garden;
|
||||
|
||||
fn main() {
|
||||
let plant = Asparagus {};
|
||||
println!("I'm growing {:?}!", plant);
|
||||
}
|
||||
```
|
||||
|
||||
The `pub mod garden;` line tells the compiler to include the code it finds in
|
||||
*src/garden.rs*, which is:
|
||||
|
||||
Filename: src/garden.rs
|
||||
|
||||
```
|
||||
pub mod vegetables;
|
||||
```
|
||||
|
||||
Here, `pub mod vegetables;` means the code in *src/garden/vegetables.rs* is
|
||||
included too. That code is:
|
||||
|
||||
```
|
||||
#[derive(Debug)]
|
||||
pub struct Asparagus {}
|
||||
```
|
||||
|
||||
Now let’s get into the details of these rules and demonstrate them in action!
|
||||
|
||||
### Grouping Related Code in Modules
|
||||
|
||||
*Modules* let us organize code within a crate for readability and easy reuse.
|
||||
Modules also allow us to control the *privacy* of items because code within a
|
||||
module is private by default. Private items are internal implementation details
|
||||
|
@ -263,8 +268,8 @@ mod front_of_house {
|
|||
}
|
||||
```
|
||||
|
||||
Listing 7-1: A `front_of_house` module containing other modules that then
|
||||
contain functions
|
||||
Listing 7-1: A `front_of_house` module containing other
|
||||
modules that then contain functions
|
||||
|
||||
We define a module with the `mod` keyword followed by the name of the module
|
||||
(in this case, `front_of_house`). The body of the module then goes inside curly
|
||||
|
@ -298,7 +303,8 @@ crate
|
|||
└── take_payment
|
||||
```
|
||||
|
||||
Listing 7-2: The module tree for the code in Listing 7-1
|
||||
Listing 7-2: The module tree for the code in Listing
|
||||
7-1
|
||||
|
||||
This tree shows how some of the modules nest inside other modules; for example,
|
||||
`hosting` nests inside `front_of_house`. The tree also shows that some modules
|
||||
|
@ -321,18 +327,19 @@ know its path.
|
|||
|
||||
A path can take two forms:
|
||||
|
||||
* An *absolute path* is the full path starting from a crate root; for code from
|
||||
an external crate, the absolute path begins with the crate name, and for code
|
||||
from the current crate, it starts with the literal `crate`.
|
||||
* An *absolute path* is the full path starting from a crate root; for code
|
||||
from an external crate, the absolute path begins with the crate name, and for
|
||||
code from the current crate, it starts with the literal `crate`.
|
||||
* A *relative path* starts from the current module and uses `self`, `super`, or
|
||||
an identifier in the current module.
|
||||
an identifier in the current module.
|
||||
|
||||
Both absolute and relative paths are followed by one or more identifiers
|
||||
separated by double colons (`::`).
|
||||
|
||||
Returning to Listing 7-1, say we want to call the `add_to_waitlist` function.
|
||||
This is the same as asking: what’s the path of the `add_to_waitlist` function?
|
||||
Listing 7-3 contains Listing 7-1 with some of the modules and functions removed.
|
||||
Listing 7-3 contains Listing 7-1 with some of the modules and functions
|
||||
removed.
|
||||
|
||||
We’ll show two ways to call the `add_to_waitlist` function from a new function,
|
||||
`eat_at_restaurant`, defined in the crate root. These paths are correct, but
|
||||
|
@ -340,8 +347,8 @@ there’s another problem remaining that will prevent this example from compilin
|
|||
as is. We’ll explain why in a bit.
|
||||
|
||||
The `eat_at_restaurant` function is part of our library crate’s public API, so
|
||||
we mark it with the `pub` keyword. In “Exposing Paths with the pub Keyword” on
|
||||
page XX, we’ll go into more detail about `pub`.
|
||||
we mark it with the `pub` keyword. In the “Exposing Paths with the `pub`
|
||||
Keyword” section, we’ll go into more detail about `pub`.
|
||||
|
||||
Filename: src/lib.rs
|
||||
|
||||
|
@ -361,8 +368,8 @@ pub fn eat_at_restaurant() {
|
|||
}
|
||||
```
|
||||
|
||||
Listing 7-3: Calling the `add_to_waitlist` function using absolute and relative
|
||||
paths
|
||||
Listing 7-3: Calling the `add_to_waitlist` function using
|
||||
absolute and relative paths
|
||||
|
||||
The first time we call the `add_to_waitlist` function in `eat_at_restaurant`,
|
||||
we use an absolute path. The `add_to_waitlist` function is defined in the same
|
||||
|
@ -403,7 +410,9 @@ error[E0603]: module `hosting` is private
|
|||
--> src/lib.rs:9:28
|
||||
|
|
||||
9 | crate::front_of_house::hosting::add_to_waitlist();
|
||||
| ^^^^^^^ private module
|
||||
| ^^^^^^^ --------------- function `add_to_waitlist` is not publicly re-exported
|
||||
| |
|
||||
| private module
|
||||
|
|
||||
note: the module `hosting` is defined here
|
||||
--> src/lib.rs:2:5
|
||||
|
@ -415,16 +424,22 @@ error[E0603]: module `hosting` is private
|
|||
--> src/lib.rs:12:21
|
||||
|
|
||||
12 | front_of_house::hosting::add_to_waitlist();
|
||||
| ^^^^^^^ private module
|
||||
| ^^^^^^^ --------------- function `add_to_waitlist` is not publicly re-exported
|
||||
| |
|
||||
| private module
|
||||
|
|
||||
note: the module `hosting` is defined here
|
||||
--> src/lib.rs:2:5
|
||||
|
|
||||
2 | mod hosting {
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
For more information about this error, try `rustc --explain E0603`.
|
||||
error: could not compile `restaurant` (lib) due to 2 previous errors
|
||||
```
|
||||
|
||||
Listing 7-4: Compiler errors from building the code in Listing 7-3
|
||||
Listing 7-4: Compiler errors from building the code in
|
||||
Listing 7-3
|
||||
|
||||
The error messages say that module `hosting` is private. In other words, we
|
||||
have the correct paths for the `hosting` module and the `add_to_waitlist`
|
||||
|
@ -447,7 +462,7 @@ inner code you can change without breaking outer code. However, Rust does give
|
|||
you the option to expose inner parts of child modules’ code to outer ancestor
|
||||
modules by using the `pub` keyword to make an item public.
|
||||
|
||||
### Exposing Paths with the pub Keyword
|
||||
### Exposing Paths with the `pub` Keyword
|
||||
|
||||
Let’s return to the error in Listing 7-4 that told us the `hosting` module is
|
||||
private. We want the `eat_at_restaurant` function in the parent module to have
|
||||
|
@ -463,11 +478,17 @@ mod front_of_house {
|
|||
}
|
||||
}
|
||||
|
||||
--snip--
|
||||
pub fn eat_at_restaurant() {
|
||||
// Absolute path
|
||||
crate::front_of_house::hosting::add_to_waitlist();
|
||||
|
||||
// Relative path
|
||||
front_of_house::hosting::add_to_waitlist();
|
||||
}
|
||||
```
|
||||
|
||||
Listing 7-5: Declaring the `hosting` module as `pub` to use it from
|
||||
`eat_at_restaurant`
|
||||
Listing 7-5: Declaring the `hosting` module as `pub` to
|
||||
use it from `eat_at_restaurant`
|
||||
|
||||
Unfortunately, the code in Listing 7-5 still results in compiler errors, as
|
||||
shown in Listing 7-6.
|
||||
|
@ -498,9 +519,13 @@ note: the function `add_to_waitlist` is defined here
|
|||
|
|
||||
3 | fn add_to_waitlist() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
For more information about this error, try `rustc --explain E0603`.
|
||||
error: could not compile `restaurant` (lib) due to 2 previous errors
|
||||
```
|
||||
|
||||
Listing 7-6: Compiler errors from building the code in Listing 7-5
|
||||
Listing 7-6: Compiler errors from building the code in
|
||||
Listing 7-5
|
||||
|
||||
What happened? Adding the `pub` keyword in front of `mod hosting` makes the
|
||||
module public. With this change, if we can access `front_of_house`, we can
|
||||
|
@ -527,11 +552,18 @@ mod front_of_house {
|
|||
}
|
||||
}
|
||||
|
||||
--snip--
|
||||
pub fn eat_at_restaurant() {
|
||||
// Absolute path
|
||||
crate::front_of_house::hosting::add_to_waitlist();
|
||||
|
||||
// Relative path
|
||||
front_of_house::hosting::add_to_waitlist();
|
||||
}
|
||||
```
|
||||
|
||||
Listing 7-7: Adding the `pub` keyword to `mod hosting` and `fn add_to_waitlist`
|
||||
lets us call the function from `eat_at_restaurant`.
|
||||
Listing 7-7: Adding the `pub` keyword to `mod hosting`
|
||||
and `fn add_to_waitlist` lets us call the function from
|
||||
`eat_at_restaurant`
|
||||
|
||||
Now the code will compile! To see why adding the `pub` keyword lets us use
|
||||
these paths in `add_to_waitlist` with respect to the privacy rules, let’s look
|
||||
|
@ -559,31 +591,31 @@ If you plan on sharing your library crate so other projects can use your code,
|
|||
your public API is your contract with users of your crate that determines how
|
||||
they can interact with your code. There are many considerations around managing
|
||||
changes to your public API to make it easier for people to depend on your
|
||||
crate. These considerations are beyond the scope of this book; if you’re
|
||||
interested in this topic, see the Rust API Guidelines at
|
||||
*https://rust-lang.github.io/api-guidelines*.
|
||||
crate. These considerations are out of the scope of this book; if you’re
|
||||
interested in this topic, see The Rust API Guidelines at *https://rust-lang.github.io/api-guidelines/*.
|
||||
|
||||
> ### Best Practices for Packages with a Binary and a Library
|
||||
> #### Best Practices for Packages with a Binary and a Library
|
||||
>
|
||||
> We mentioned that a package can contain both a *src/main.rs* binary crate
|
||||
root as well as a *src/lib.rs* library crate root, and both crates will have
|
||||
the package name by default. Typically, packages with this pattern of
|
||||
containing both a library and a binary crate will have just enough code in the
|
||||
binary crate to start an executable that calls code with the library crate.
|
||||
This lets other projects benefit from the most functionality that the package
|
||||
provides because the library crate’s code can be shared.
|
||||
> root as well as a *src/lib.rs* library crate root, and both crates will have
|
||||
> the package name by default. Typically, packages with this pattern of
|
||||
> containing both a library and a binary crate will have just enough code in the
|
||||
> binary crate to start an executable that calls code within the library crate.
|
||||
> This lets other projects benefit from most of the functionality that the
|
||||
> package provides because the library crate’s code can be shared.
|
||||
>
|
||||
> The module tree should be defined in *src/lib.rs*. Then, any public items can
|
||||
be used in the binary crate by starting paths with the name of the package. The
|
||||
binary crate becomes a user of the library crate just like a completely
|
||||
external crate would use the library crate: it can only use the public API.
|
||||
This helps you design a good API; not only are you the author, you’re also a
|
||||
client!
|
||||
> be used in the binary crate by starting paths with the name of the package.
|
||||
> The binary crate becomes a user of the library crate just like a completely
|
||||
> external crate would use the library crate: it can only use the public API.
|
||||
> This helps you design a good API; not only are you the author, you’re also a
|
||||
> client!
|
||||
>
|
||||
> In Chapter 12, we’ll demonstrate this organizational practice with a command
|
||||
line program that will contain both a binary crate and a library crate.
|
||||
> In Chapter 12, we’ll demonstrate this organizational
|
||||
> practice with a command-line program that will contain both a binary crate
|
||||
> and a library crate.
|
||||
|
||||
### Starting Relative Paths with super
|
||||
### Starting Relative Paths with `super`
|
||||
|
||||
We can construct relative paths that begin in the parent module, rather than
|
||||
the current module or the crate root, by using `super` at the start of the
|
||||
|
@ -614,7 +646,8 @@ mod back_of_house {
|
|||
}
|
||||
```
|
||||
|
||||
Listing 7-8: Calling a function using a relative path starting with `super`
|
||||
Listing 7-8: Calling a function using a relative path
|
||||
starting with `super`
|
||||
|
||||
The `fix_incorrect_order` function is in the `back_of_house` module, so we can
|
||||
use `super` to go to the parent module of `back_of_house`, which in this case
|
||||
|
@ -664,14 +697,14 @@ pub fn eat_at_restaurant() {
|
|||
meal.toast = String::from("Wheat");
|
||||
println!("I'd like {} toast please", meal.toast);
|
||||
|
||||
// The next line won't compile if we uncomment it; we're not
|
||||
// allowed to see or modify the seasonal fruit that comes
|
||||
// with the meal
|
||||
// The next line won't compile if we uncomment it; we're not allowed
|
||||
// to see or modify the seasonal fruit that comes with the meal
|
||||
// meal.seasonal_fruit = String::from("blueberries");
|
||||
}
|
||||
```
|
||||
|
||||
Listing 7-9: A struct with some public fields and some private fields
|
||||
Listing 7-9: A struct with some public fields and some
|
||||
private fields
|
||||
|
||||
Because the `toast` field in the `back_of_house::Breakfast` struct is public,
|
||||
in `eat_at_restaurant` we can write and read to the `toast` field using dot
|
||||
|
@ -705,7 +738,8 @@ pub fn eat_at_restaurant() {
|
|||
}
|
||||
```
|
||||
|
||||
Listing 7-10: Designating an enum as public makes all its variants public.
|
||||
Listing 7-10: Designating an enum as public makes all its
|
||||
variants public
|
||||
|
||||
Because we made the `Appetizer` enum public, we can use the `Soup` and `Salad`
|
||||
variants in `eat_at_restaurant`.
|
||||
|
@ -720,7 +754,7 @@ There’s one more situation involving `pub` that we haven’t covered, and that
|
|||
our last module system feature: the `use` keyword. We’ll cover `use` by itself
|
||||
first, and then we’ll show how to combine `pub` and `use`.
|
||||
|
||||
## Bringing Paths into Scope with the use Keyword
|
||||
## Bringing Paths into Scope with the `use` Keyword
|
||||
|
||||
Having to write out the paths to call functions can feel inconvenient and
|
||||
repetitive. In Listing 7-7, whether we chose the absolute or relative path to
|
||||
|
@ -750,7 +784,8 @@ pub fn eat_at_restaurant() {
|
|||
}
|
||||
```
|
||||
|
||||
Listing 7-11: Bringing a module into scope with `use`
|
||||
Listing 7-11: Bringing a module into scope with
|
||||
`use`
|
||||
|
||||
Adding `use` and a path in a scope is similar to creating a symbolic link in
|
||||
the filesystem. By adding `use crate::front_of_house::hosting` in the crate
|
||||
|
@ -781,17 +816,25 @@ mod customer {
|
|||
}
|
||||
```
|
||||
|
||||
Listing 7-12: A `use` statement only applies in the scope it’s in.
|
||||
Listing 7-12: A `use` statement only applies in the scope
|
||||
it’s in
|
||||
|
||||
The compiler error shows that the shortcut no longer applies within the
|
||||
`customer` module:
|
||||
|
||||
```
|
||||
$ cargo build
|
||||
Compiling restaurant v0.1.0 (file:///projects/restaurant)
|
||||
error[E0433]: failed to resolve: use of undeclared crate or module `hosting`
|
||||
--> src/lib.rs:11:9
|
||||
|
|
||||
11 | hosting::add_to_waitlist();
|
||||
| ^^^^^^^ use of undeclared crate or module `hosting`
|
||||
|
|
||||
help: consider importing this module through its public re-export
|
||||
|
|
||||
10 + use crate::hosting;
|
||||
|
|
||||
|
||||
warning: unused import: `crate::front_of_house::hosting`
|
||||
--> src/lib.rs:7:5
|
||||
|
@ -800,6 +843,10 @@ warning: unused import: `crate::front_of_house::hosting`
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(unused_imports)]` on by default
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
||||
warning: `restaurant` (lib) generated 1 warning
|
||||
error: could not compile `restaurant` (lib) due to 1 previous error; 1 warning emitted
|
||||
```
|
||||
|
||||
Notice there’s also a warning that the `use` is no longer used in its scope! To
|
||||
|
@ -807,7 +854,7 @@ fix this problem, move the `use` within the `customer` module too, or reference
|
|||
the shortcut in the parent module with `super::hosting` within the child
|
||||
`customer` module.
|
||||
|
||||
### Creating Idiomatic use Paths
|
||||
### Creating Idiomatic `use` Paths
|
||||
|
||||
In Listing 7-11, you might have wondered why we specified `use
|
||||
crate::front_of_house::hosting` and then called `hosting::add_to_waitlist` in
|
||||
|
@ -830,8 +877,8 @@ pub fn eat_at_restaurant() {
|
|||
}
|
||||
```
|
||||
|
||||
Listing 7-13: Bringing the `add_to_waitlist` function into scope with `use`,
|
||||
which is unidiomatic
|
||||
Listing 7-13: Bringing the `add_to_waitlist` function
|
||||
into scope with `use`, which is unidiomatic
|
||||
|
||||
Although both Listing 7-11 and Listing 7-13 accomplish the same task, Listing
|
||||
7-11 is the idiomatic way to bring a function into scope with `use`. Bringing
|
||||
|
@ -857,7 +904,8 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
Listing 7-14: Bringing `HashMap` into scope in an idiomatic way
|
||||
Listing 7-14: Bringing `HashMap` into scope in an
|
||||
idiomatic way
|
||||
|
||||
There’s no strong reason behind this idiom: it’s just the convention that has
|
||||
emerged, and folks have gotten used to reading and writing Rust code this way.
|
||||
|
@ -874,23 +922,23 @@ use std::fmt;
|
|||
use std::io;
|
||||
|
||||
fn function1() -> fmt::Result {
|
||||
--snip--
|
||||
// --snip--
|
||||
}
|
||||
|
||||
fn function2() -> io::Result<()> {
|
||||
--snip--
|
||||
// --snip--
|
||||
}
|
||||
```
|
||||
|
||||
Listing 7-15: Bringing two types with the same name into the same scope
|
||||
requires using their parent modules.
|
||||
Listing 7-15: Bringing two types with the same name into
|
||||
the same scope requires using their parent modules.
|
||||
|
||||
As you can see, using the parent modules distinguishes the two `Result` types.
|
||||
If instead we specified `use std::fmt::Result` and `use std::io::Result`, we’d
|
||||
have two `Result` types in the same scope, and Rust wouldn’t know which one we
|
||||
meant when we used `Result`.
|
||||
|
||||
### Providing New Names with the as Keyword
|
||||
### Providing New Names with the `as` Keyword
|
||||
|
||||
There’s another solution to the problem of bringing two types of the same name
|
||||
into the same scope with `use`: after the path, we can specify `as` and a new
|
||||
|
@ -904,22 +952,23 @@ use std::fmt::Result;
|
|||
use std::io::Result as IoResult;
|
||||
|
||||
fn function1() -> Result {
|
||||
--snip--
|
||||
// --snip--
|
||||
}
|
||||
|
||||
fn function2() -> IoResult<()> {
|
||||
--snip--
|
||||
// --snip--
|
||||
}
|
||||
```
|
||||
|
||||
Listing 7-16: Renaming a type when it’s brought into scope with the `as` keyword
|
||||
Listing 7-16: Renaming a type when it’s brought into
|
||||
scope with the `as` keyword
|
||||
|
||||
In the second `use` statement, we chose the new name `IoResult` for the
|
||||
`std::io::Result` type, which won’t conflict with the `Result` from `std::fmt`
|
||||
that we’ve also brought into scope. Listing 7-15 and Listing 7-16 are
|
||||
considered idiomatic, so the choice is up to you!
|
||||
|
||||
### Re-exporting Names with pub use
|
||||
### Re-exporting Names with `pub use`
|
||||
|
||||
When we bring a name into scope with the `use` keyword, the name available in
|
||||
the new scope is private. To enable the code that calls our code to refer to
|
||||
|
@ -947,12 +996,13 @@ pub fn eat_at_restaurant() {
|
|||
}
|
||||
```
|
||||
|
||||
Listing 7-17: Making a name available for any code to use from a new scope with
|
||||
`pub use`
|
||||
Listing 7-17: Making a name available for any code to use
|
||||
from a new scope with `pub use`
|
||||
|
||||
Before this change, external code would have to call the `add_to_waitlist`
|
||||
function by using the path
|
||||
`restaurant::front_of_house::hosting::add_to_waitlist()`. Now that this `pub
|
||||
`restaurant::front_of_house::hosting::add_to_waitlist()`, which also would have
|
||||
required the `front_of_house` module to be marked as `pub`. Now that this `pub
|
||||
use` has re-exported the `hosting` module from the root module, external code
|
||||
can use the path `restaurant::hosting::add_to_waitlist()` instead.
|
||||
|
||||
|
@ -964,8 +1014,9 @@ probably won’t think about the parts of the restaurant in those terms. With
|
|||
`pub use`, we can write our code with one structure but expose a different
|
||||
structure. Doing so makes our library well organized for programmers working on
|
||||
the library and programmers calling the library. We’ll look at another example
|
||||
of `pub use` and how it affects your crate’s documentation in “Exporting a
|
||||
Convenient Public API with pub use” on page XX.
|
||||
of `pub use` and how it affects your crate’s documentation in the “Exporting a
|
||||
Convenient Public API with `pub use`” section of
|
||||
Chapter 14.
|
||||
|
||||
### Using External Packages
|
||||
|
||||
|
@ -973,6 +1024,12 @@ In Chapter 2, we programmed a guessing game project that used an external
|
|||
package called `rand` to get random numbers. To use `rand` in our project, we
|
||||
added this line to *Cargo.toml*:
|
||||
|
||||
<!-- When updating the version of `rand` used, also update the version of
|
||||
`rand` used in these files so they all match:
|
||||
* ch02-00-guessing-game-tutorial.md
|
||||
* ch14-03-cargo-workspaces.md
|
||||
-->
|
||||
|
||||
Filename: Cargo.toml
|
||||
|
||||
```
|
||||
|
@ -980,14 +1037,14 @@ rand = "0.8.5"
|
|||
```
|
||||
|
||||
Adding `rand` as a dependency in *Cargo.toml* tells Cargo to download the
|
||||
`rand` package and any dependencies from *https://crates.io*, and make `rand`
|
||||
available to our project.
|
||||
`rand` package and any dependencies from crates.io at *https://crates.io/* and
|
||||
make `rand` available to our project.
|
||||
|
||||
Then, to bring `rand` definitions into the scope of our package, we added a
|
||||
`use` line starting with the name of the crate, `rand`, and listed the items we
|
||||
wanted to bring into scope. Recall that in “Generating a Random Number” on page
|
||||
XX, we brought the `Rng` trait into scope and called the `rand::thread_rng`
|
||||
function:
|
||||
`use` line starting with the name of the crate, `rand`, and listed the items
|
||||
we wanted to bring into scope. Recall that in the “Generating a Random
|
||||
Number” section in Chapter 2, we brought the `Rng` trait
|
||||
into scope and called the `rand::thread_rng` function:
|
||||
|
||||
```
|
||||
use rand::Rng;
|
||||
|
@ -998,9 +1055,9 @@ fn main() {
|
|||
```
|
||||
|
||||
Members of the Rust community have made many packages available at
|
||||
*https://crates.io*, and pulling any of them into your package involves these
|
||||
same steps: listing them in your package’s *Cargo.toml* file and using `use` to
|
||||
bring items from their crates into scope.
|
||||
crates.io at *https://crates.io/*, and pulling any of them into your package
|
||||
involves these same steps: listing them in your package’s *Cargo.toml* file and
|
||||
using `use` to bring items from their crates into scope.
|
||||
|
||||
Note that the standard `std` library is also a crate that’s external to our
|
||||
package. Because the standard library is shipped with the Rust language, we
|
||||
|
@ -1015,7 +1072,7 @@ use std::collections::HashMap;
|
|||
This is an absolute path starting with `std`, the name of the standard library
|
||||
crate.
|
||||
|
||||
### Using Nested Paths to Clean Up Large use Lists
|
||||
### Using Nested Paths to Clean Up Large `use` Lists
|
||||
|
||||
If we’re using multiple items defined in the same crate or same module, listing
|
||||
each item on its own line can take up a lot of vertical space in our files. For
|
||||
|
@ -1025,10 +1082,10 @@ bring items from `std` into scope:
|
|||
Filename: src/main.rs
|
||||
|
||||
```
|
||||
--snip--
|
||||
// --snip--
|
||||
use std::cmp::Ordering;
|
||||
use std::io;
|
||||
--snip--
|
||||
// --snip--
|
||||
```
|
||||
|
||||
Instead, we can use nested paths to bring the same items into scope in one
|
||||
|
@ -1039,13 +1096,13 @@ differ, as shown in Listing 7-18.
|
|||
Filename: src/main.rs
|
||||
|
||||
```
|
||||
--snip--
|
||||
// --snip--
|
||||
use std::{cmp::Ordering, io};
|
||||
--snip--
|
||||
// --snip--
|
||||
```
|
||||
|
||||
Listing 7-18: Specifying a nested path to bring multiple items with the same
|
||||
prefix into scope
|
||||
Listing 7-18: Specifying a nested path to bring multiple
|
||||
items with the same prefix into scope
|
||||
|
||||
In bigger programs, bringing many items into scope from the same crate or
|
||||
module using nested paths can reduce the number of separate `use` statements
|
||||
|
@ -1063,7 +1120,8 @@ use std::io;
|
|||
use std::io::Write;
|
||||
```
|
||||
|
||||
Listing 7-19: Two `use` statements where one is a subpath of the other
|
||||
Listing 7-19: Two `use` statements where one is a subpath
|
||||
of the other
|
||||
|
||||
The common part of these two paths is `std::io`, and that’s the complete first
|
||||
path. To merge these two paths into one `use` statement, we can use `self` in
|
||||
|
@ -1075,7 +1133,8 @@ Filename: src/lib.rs
|
|||
use std::io::{self, Write};
|
||||
```
|
||||
|
||||
Listing 7-20: Combining the paths in Listing 7-19 into one `use` statement
|
||||
Listing 7-20: Combining the paths in Listing 7-19 into
|
||||
one `use` statement
|
||||
|
||||
This line brings `std::io` and `std::io::Write` into scope.
|
||||
|
||||
|
@ -1094,9 +1153,11 @@ harder to tell what names are in scope and where a name used in your program
|
|||
was defined.
|
||||
|
||||
The glob operator is often used when testing to bring everything under test
|
||||
into the `tests` module; we’ll talk about that in “How to Write Tests” on page
|
||||
XX. The glob operator is also sometimes used as part of the prelude pattern:
|
||||
see the standard library documentation for more information on that pattern.
|
||||
into the `tests` module; we’ll talk about that in the “How to Write
|
||||
Tests” section in Chapter 11. The glob operator
|
||||
is also sometimes used as part of the prelude pattern: see the standard
|
||||
library documentation
|
||||
for more information on that pattern.
|
||||
|
||||
## Separating Modules into Different Files
|
||||
|
||||
|
@ -1128,8 +1189,8 @@ pub fn eat_at_restaurant() {
|
|||
}
|
||||
```
|
||||
|
||||
Listing 7-21: Declaring the `front_of_house` module whose body will be in
|
||||
*src/front_of_house.rs*
|
||||
Listing 7-21: Declaring the `front_of_house` module whose
|
||||
body will be in *src/front_of_house.rs*
|
||||
|
||||
Next, place the code that was in the curly brackets into a new file named
|
||||
*src/front_of_house.rs*, as shown in Listing 7-22. The compiler knows to look
|
||||
|
@ -1144,16 +1205,17 @@ pub mod hosting {
|
|||
}
|
||||
```
|
||||
|
||||
Listing 7-22: Definitions inside the `front_of_house` module in
|
||||
*src/front_of_house.rs*
|
||||
Listing 7-22: Definitions inside the `front_of_house`
|
||||
module in *src/front_of_house.rs*
|
||||
|
||||
Note that you only need to load a file using a `mod` declaration *once* in your
|
||||
module tree. Once the compiler knows the file is part of the project (and knows
|
||||
where in the module tree the code resides because of where you’ve put the `mod`
|
||||
statement), other files in your project should refer to the loaded file’s code
|
||||
using a path to where it was declared, as covered in “Paths for Referring to an
|
||||
Item in the Module Tree” on page XX. In other words, `mod` is *not* an
|
||||
“include” operation that you may have seen in other programming languages.
|
||||
using a path to where it was declared, as covered in the “Paths for Referring
|
||||
to an Item in the Module Tree” section. In other words,
|
||||
`mod` is *not* an “include” operation that you may have seen in other
|
||||
programming languages.
|
||||
|
||||
Next, we’ll extract the `hosting` module to its own file. The process is a bit
|
||||
different because `hosting` is a child module of `front_of_house`, not of the
|
||||
|
@ -1187,26 +1249,26 @@ directories and files more closely match the module tree.
|
|||
> ### Alternate File Paths
|
||||
>
|
||||
> So far we’ve covered the most idiomatic file paths the Rust compiler uses,
|
||||
but Rust also supports an older style of file path. For a module named
|
||||
`front_of_house` declared in the crate root, the compiler will look for the
|
||||
module’s code in:
|
||||
> but Rust also supports an older style of file path. For a module named
|
||||
> `front_of_house` declared in the crate root, the compiler will look for the
|
||||
> module’s code in:
|
||||
>
|
||||
> * *src/front_of_house.rs* (what we covered)
|
||||
> * *src/front_of_house/mod.rs* (older style, still supported path)
|
||||
>
|
||||
> For a module named `hosting` that is a submodule of `front_of_house`, the
|
||||
compiler will look for the module’s code in:
|
||||
> compiler will look for the module’s code in:
|
||||
>
|
||||
> * *src/front_of_house/hosting.rs* (what we covered)
|
||||
> * *src/front_of_house/hosting/mod.rs* (older style, still supported path)
|
||||
>
|
||||
> If you use both styles for the same module, you’ll get a compiler error.
|
||||
Using a mix of both styles for different modules in the same project is
|
||||
allowed, but might be confusing for people navigating your project.
|
||||
> Using a mix of both styles for different modules in the same project is
|
||||
> allowed, but might be confusing for people navigating your project.
|
||||
>
|
||||
> The main downside to the style that uses files named *mod.rs* is that your
|
||||
project can end up with many files named *mod.rs*, which can get confusing when
|
||||
you have them open in your editor at the same time.
|
||||
> project can end up with many files named *mod.rs*, which can get confusing
|
||||
> when you have them open in your editor at the same time.
|
||||
|
||||
We’ve moved each module’s code to a separate file, and the module tree remains
|
||||
the same. The function calls in `eat_at_restaurant` will work without any
|
||||
|
@ -1230,4 +1292,3 @@ definitions public by adding the `pub` keyword.
|
|||
|
||||
In the next chapter, we’ll look at some collection data structures in the
|
||||
standard library that you can use in your neatly organized code.
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue