mirror of
https://github.com/rust-lang/book.git
synced 2026-05-17 17:52:12 -04:00
Merge remote-tracking branch 'origin/ch13'
This commit is contained in:
@@ -60,6 +60,7 @@ BoxMeUp
|
||||
BTreeSet
|
||||
BuildHasher
|
||||
Cacher
|
||||
cacher
|
||||
Cagain
|
||||
callsite
|
||||
CamelCase
|
||||
@@ -429,6 +430,7 @@ SelectBox
|
||||
semver
|
||||
SemVer
|
||||
serde
|
||||
ShirtColor
|
||||
ShlAssign
|
||||
ShrAssign
|
||||
shouldn
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "workout-app"
|
||||
version = "0.1.0"
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "shirt-company"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "workout-app"
|
||||
name = "shirt-company"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
$ cargo run
|
||||
Compiling shirt-company v0.1.0 (file:///projects/shirt-company)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.27s
|
||||
Running `target/debug/shirt-company`
|
||||
The user with preference Some(Red) gets Red
|
||||
The user with preference None gets Blue
|
||||
@@ -1,12 +1,52 @@
|
||||
// ANCHOR: here
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
fn simulated_expensive_calculation(intensity: u32) -> u32 {
|
||||
println!("calculating slowly...");
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
intensity
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
enum ShirtColor {
|
||||
Red,
|
||||
Blue,
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
|
||||
fn main() {}
|
||||
struct Inventory {
|
||||
shirts: Vec<ShirtColor>,
|
||||
}
|
||||
|
||||
impl Inventory {
|
||||
fn giveaway(&self, user_preference: Option<ShirtColor>) -> ShirtColor {
|
||||
user_preference.unwrap_or_else(|| self.most_stocked())
|
||||
}
|
||||
|
||||
fn most_stocked(&self) -> ShirtColor {
|
||||
let mut num_red = 0;
|
||||
let mut num_blue = 0;
|
||||
|
||||
for color in &self.shirts {
|
||||
match color {
|
||||
ShirtColor::Red => num_red += 1,
|
||||
ShirtColor::Blue => num_blue += 1,
|
||||
}
|
||||
}
|
||||
if num_red > num_blue {
|
||||
ShirtColor::Red
|
||||
} else {
|
||||
ShirtColor::Blue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let store = Inventory {
|
||||
shirts: vec![ShirtColor::Blue, ShirtColor::Red, ShirtColor::Blue],
|
||||
};
|
||||
|
||||
let user_pref1 = Some(ShirtColor::Red);
|
||||
let giveaway1 = store.giveaway(user_pref1);
|
||||
println!(
|
||||
"The user with preference {:?} gets {:?}",
|
||||
user_pref1, giveaway1
|
||||
);
|
||||
|
||||
let user_pref2 = None;
|
||||
let giveaway2 = store.giveaway(user_pref2);
|
||||
println!(
|
||||
"The user with preference {:?} gets {:?}",
|
||||
user_pref2, giveaway2
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,33 @@
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
fn simulated_expensive_calculation(intensity: u32) -> u32 {
|
||||
println!("calculating slowly...");
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
intensity
|
||||
fn generate_workout(intensity: u32, random_number: u32) {
|
||||
// ANCHOR: here
|
||||
let expensive_closure = |num: u32| -> u32 {
|
||||
println!("calculating slowly...");
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
num
|
||||
};
|
||||
// ANCHOR_END: here
|
||||
|
||||
if intensity < 25 {
|
||||
println!("Today, do {} pushups!", expensive_closure(intensity));
|
||||
println!("Next, do {} situps!", expensive_closure(intensity));
|
||||
} else {
|
||||
if random_number == 3 {
|
||||
println!("Take a break today! Remember to stay hydrated!");
|
||||
} else {
|
||||
println!(
|
||||
"Today, run for {} minutes!",
|
||||
expensive_closure(intensity)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_workout(intensity: u32, random_number: u32) {}
|
||||
|
||||
// ANCHOR: here
|
||||
fn main() {
|
||||
let simulated_user_specified_value = 10;
|
||||
let simulated_random_number = 7;
|
||||
|
||||
generate_workout(simulated_user_specified_value, simulated_random_number);
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "workout-app"
|
||||
name = "closure-example"
|
||||
version = "0.1.0"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "workout-app"
|
||||
name = "closure-example"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
12
listings/ch13-functional-features/listing-13-03/output.txt
Normal file
12
listings/ch13-functional-features/listing-13-03/output.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
$ cargo run
|
||||
Compiling closure-example v0.1.0 (file:///projects/closure-example)
|
||||
error[E0308]: mismatched types
|
||||
--> src/main.rs:5:29
|
||||
|
|
||||
5 | let n = example_closure(5);
|
||||
| ^- help: try using a conversion method: `.to_string()`
|
||||
| |
|
||||
| expected struct `String`, found integer
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
error: could not compile `closure-example` due to previous error
|
||||
@@ -1,39 +1,8 @@
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
fn simulated_expensive_calculation(intensity: u32) -> u32 {
|
||||
println!("calculating slowly...");
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
intensity
|
||||
}
|
||||
|
||||
// ANCHOR: here
|
||||
fn generate_workout(intensity: u32, random_number: u32) {
|
||||
if intensity < 25 {
|
||||
println!(
|
||||
"Today, do {} pushups!",
|
||||
simulated_expensive_calculation(intensity)
|
||||
);
|
||||
println!(
|
||||
"Next, do {} situps!",
|
||||
simulated_expensive_calculation(intensity)
|
||||
);
|
||||
} else {
|
||||
if random_number == 3 {
|
||||
println!("Take a break today! Remember to stay hydrated!");
|
||||
} else {
|
||||
println!(
|
||||
"Today, run for {} minutes!",
|
||||
simulated_expensive_calculation(intensity)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
|
||||
fn main() {
|
||||
let simulated_user_specified_value = 10;
|
||||
let simulated_random_number = 7;
|
||||
// ANCHOR: here
|
||||
let example_closure = |x| x;
|
||||
|
||||
generate_workout(simulated_user_specified_value, simulated_random_number);
|
||||
let s = example_closure(String::from("hello"));
|
||||
let n = example_closure(5);
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "workout-app"
|
||||
name = "closure-example"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
$ cargo run
|
||||
Compiling closure-example v0.1.0 (file:///projects/closure-example)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.43s
|
||||
Running `target/debug/closure-example`
|
||||
Before defining closure: [1, 2, 3]
|
||||
Before calling closure: [1, 2, 3]
|
||||
From closure: [1, 2, 3]
|
||||
After calling closure: [1, 2, 3]
|
||||
@@ -1,32 +1,10 @@
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
fn simulated_expensive_calculation(intensity: u32) -> u32 {
|
||||
println!("calculating slowly...");
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
intensity
|
||||
}
|
||||
|
||||
// ANCHOR: here
|
||||
fn generate_workout(intensity: u32, random_number: u32) {
|
||||
let expensive_result = simulated_expensive_calculation(intensity);
|
||||
|
||||
if intensity < 25 {
|
||||
println!("Today, do {} pushups!", expensive_result);
|
||||
println!("Next, do {} situps!", expensive_result);
|
||||
} else {
|
||||
if random_number == 3 {
|
||||
println!("Take a break today! Remember to stay hydrated!");
|
||||
} else {
|
||||
println!("Today, run for {} minutes!", expensive_result);
|
||||
}
|
||||
}
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
|
||||
fn main() {
|
||||
let simulated_user_specified_value = 10;
|
||||
let simulated_random_number = 7;
|
||||
let list = vec![1, 2, 3];
|
||||
println!("Before defining closure: {:?}", list);
|
||||
|
||||
generate_workout(simulated_user_specified_value, simulated_random_number);
|
||||
let only_borrows = || println!("From closure: {:?}", list);
|
||||
|
||||
println!("Before calling closure: {:?}", list);
|
||||
only_borrows();
|
||||
println!("After calling closure: {:?}", list);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "workout-app"
|
||||
name = "closure-example"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
$ cargo run
|
||||
Compiling closure-example v0.1.0 (file:///projects/closure-example)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.43s
|
||||
Running `target/debug/closure-example`
|
||||
Before defining closure: [1, 2, 3]
|
||||
After calling closure: [1, 2, 3, 7]
|
||||
@@ -1,33 +1,9 @@
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
fn generate_workout(intensity: u32, random_number: u32) {
|
||||
// ANCHOR: here
|
||||
let expensive_closure = |num| {
|
||||
println!("calculating slowly...");
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
num
|
||||
};
|
||||
// ANCHOR_END: here
|
||||
|
||||
if intensity < 25 {
|
||||
println!("Today, do {} pushups!", expensive_closure(intensity));
|
||||
println!("Next, do {} situps!", expensive_closure(intensity));
|
||||
} else {
|
||||
if random_number == 3 {
|
||||
println!("Take a break today! Remember to stay hydrated!");
|
||||
} else {
|
||||
println!(
|
||||
"Today, run for {} minutes!",
|
||||
expensive_closure(intensity)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let simulated_user_specified_value = 10;
|
||||
let simulated_random_number = 7;
|
||||
let mut list = vec![1, 2, 3];
|
||||
println!("Before defining closure: {:?}", list);
|
||||
|
||||
generate_workout(simulated_user_specified_value, simulated_random_number);
|
||||
let mut borrows_mutably = || list.push(7);
|
||||
|
||||
borrows_mutably();
|
||||
println!("After calling closure: {:?}", list);
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "workout-app"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
[package]
|
||||
name = "workout-app"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -1,33 +0,0 @@
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
// ANCHOR: here
|
||||
fn generate_workout(intensity: u32, random_number: u32) {
|
||||
let expensive_closure = |num| {
|
||||
println!("calculating slowly...");
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
num
|
||||
};
|
||||
|
||||
if intensity < 25 {
|
||||
println!("Today, do {} pushups!", expensive_closure(intensity));
|
||||
println!("Next, do {} situps!", expensive_closure(intensity));
|
||||
} else {
|
||||
if random_number == 3 {
|
||||
println!("Take a break today! Remember to stay hydrated!");
|
||||
} else {
|
||||
println!(
|
||||
"Today, run for {} minutes!",
|
||||
expensive_closure(intensity)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
|
||||
fn main() {
|
||||
let simulated_user_specified_value = 10;
|
||||
let simulated_random_number = 7;
|
||||
|
||||
generate_workout(simulated_user_specified_value, simulated_random_number);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "workout-app"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "workout-app"
|
||||
name = "rectangles"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
18
listings/ch13-functional-features/listing-13-07/output.txt
Normal file
18
listings/ch13-functional-features/listing-13-07/output.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
$ cargo run
|
||||
Compiling rectangles v0.1.0 (file:///projects/rectangles)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.41s
|
||||
Running `target/debug/rectangles`
|
||||
[
|
||||
Rectangle {
|
||||
width: 3,
|
||||
height: 5,
|
||||
},
|
||||
Rectangle {
|
||||
width: 7,
|
||||
height: 12,
|
||||
},
|
||||
Rectangle {
|
||||
width: 10,
|
||||
height: 1,
|
||||
},
|
||||
]
|
||||
@@ -1,33 +1,25 @@
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
fn generate_workout(intensity: u32, random_number: u32) {
|
||||
// ANCHOR: here
|
||||
let expensive_closure = |num: u32| -> u32 {
|
||||
println!("calculating slowly...");
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
num
|
||||
};
|
||||
// ANCHOR_END: here
|
||||
|
||||
if intensity < 25 {
|
||||
println!("Today, do {} pushups!", expensive_closure(intensity));
|
||||
println!("Next, do {} situps!", expensive_closure(intensity));
|
||||
} else {
|
||||
if random_number == 3 {
|
||||
println!("Take a break today! Remember to stay hydrated!");
|
||||
} else {
|
||||
println!(
|
||||
"Today, run for {} minutes!",
|
||||
expensive_closure(intensity)
|
||||
);
|
||||
}
|
||||
}
|
||||
#[derive(Debug)]
|
||||
struct Rectangle {
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let simulated_user_specified_value = 10;
|
||||
let simulated_random_number = 7;
|
||||
let mut list = [
|
||||
Rectangle {
|
||||
width: 10,
|
||||
height: 1,
|
||||
},
|
||||
Rectangle {
|
||||
width: 3,
|
||||
height: 5,
|
||||
},
|
||||
Rectangle {
|
||||
width: 7,
|
||||
height: 12,
|
||||
},
|
||||
];
|
||||
|
||||
generate_workout(simulated_user_specified_value, simulated_random_number);
|
||||
list.sort_by_key(|r| r.width);
|
||||
println!("{:#?}", list);
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "closure-example"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
[package]
|
||||
name = "closure-example"
|
||||
name = "rectangles"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
$ cargo run
|
||||
Compiling closure-example v0.1.0 (file:///projects/closure-example)
|
||||
error[E0308]: mismatched types
|
||||
--> src/main.rs:5:29
|
||||
|
|
||||
5 | let n = example_closure(5);
|
||||
| ^- help: try using a conversion method: `.to_string()`
|
||||
| |
|
||||
| expected struct `String`, found integer
|
||||
Compiling rectangles v0.1.0 (file:///projects/rectangles)
|
||||
error[E0507]: cannot move out of `value`, a captured variable in an `FnMut` closure
|
||||
--> src/main.rs:27:30
|
||||
|
|
||||
24 | let value = String::from("by key called");
|
||||
| ----- captured outer variable
|
||||
25 |
|
||||
26 | list.sort_by_key(|r| {
|
||||
| ______________________-
|
||||
27 | | sort_operations.push(value);
|
||||
| | ^^^^^ move occurs because `value` has type `String`, which does not implement the `Copy` trait
|
||||
28 | | r.width
|
||||
29 | | });
|
||||
| |_____- captured by this `FnMut` closure
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
error: could not compile `closure-example` due to previous error
|
||||
For more information about this error, try `rustc --explain E0507`.
|
||||
error: could not compile `rectangles` due to previous error
|
||||
|
||||
@@ -1,8 +1,31 @@
|
||||
fn main() {
|
||||
// ANCHOR: here
|
||||
let example_closure = |x| x;
|
||||
|
||||
let s = example_closure(String::from("hello"));
|
||||
let n = example_closure(5);
|
||||
// ANCHOR_END: here
|
||||
#[derive(Debug)]
|
||||
struct Rectangle {
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut list = [
|
||||
Rectangle {
|
||||
width: 10,
|
||||
height: 1,
|
||||
},
|
||||
Rectangle {
|
||||
width: 3,
|
||||
height: 5,
|
||||
},
|
||||
Rectangle {
|
||||
width: 7,
|
||||
height: 12,
|
||||
},
|
||||
];
|
||||
|
||||
let mut sort_operations = vec![];
|
||||
let value = String::from("by key called");
|
||||
|
||||
list.sort_by_key(|r| {
|
||||
sort_operations.push(value);
|
||||
r.width
|
||||
});
|
||||
println!("{:#?}", list);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "cacher"
|
||||
name = "rectangles"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -1,11 +1,29 @@
|
||||
// ANCHOR: here
|
||||
struct Cacher<T>
|
||||
where
|
||||
T: Fn(u32) -> u32,
|
||||
{
|
||||
calculation: T,
|
||||
value: Option<u32>,
|
||||
#[derive(Debug)]
|
||||
struct Rectangle {
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
|
||||
fn main() {}
|
||||
fn main() {
|
||||
let mut list = [
|
||||
Rectangle {
|
||||
width: 10,
|
||||
height: 1,
|
||||
},
|
||||
Rectangle {
|
||||
width: 3,
|
||||
height: 5,
|
||||
},
|
||||
Rectangle {
|
||||
width: 7,
|
||||
height: 12,
|
||||
},
|
||||
];
|
||||
|
||||
let mut num_sort_operations = 0;
|
||||
list.sort_by_key(|r| {
|
||||
num_sort_operations += 1;
|
||||
r.width
|
||||
});
|
||||
println!("{:#?}, sorted in {num_sort_operations} operations", list);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "cacher"
|
||||
name = "iterators"
|
||||
version = "0.1.0"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "cacher"
|
||||
name = "iterators"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -1,34 +1,7 @@
|
||||
struct Cacher<T>
|
||||
where
|
||||
T: Fn(u32) -> u32,
|
||||
{
|
||||
calculation: T,
|
||||
value: Option<u32>,
|
||||
fn main() {
|
||||
// ANCHOR: here
|
||||
let v1 = vec![1, 2, 3];
|
||||
|
||||
let v1_iter = v1.iter();
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
||||
// ANCHOR: here
|
||||
impl<T> Cacher<T>
|
||||
where
|
||||
T: Fn(u32) -> u32,
|
||||
{
|
||||
fn new(calculation: T) -> Cacher<T> {
|
||||
Cacher {
|
||||
calculation,
|
||||
value: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn value(&mut self, arg: u32) -> u32 {
|
||||
match self.value {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
let v = (self.calculation)(arg);
|
||||
self.value = Some(v);
|
||||
v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "workout-app"
|
||||
name = "iterators"
|
||||
version = "0.1.0"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "workout-app"
|
||||
name = "iterators"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -1,64 +1,11 @@
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
struct Cacher<T>
|
||||
where
|
||||
T: Fn(u32) -> u32,
|
||||
{
|
||||
calculation: T,
|
||||
value: Option<u32>,
|
||||
}
|
||||
|
||||
impl<T> Cacher<T>
|
||||
where
|
||||
T: Fn(u32) -> u32,
|
||||
{
|
||||
fn new(calculation: T) -> Cacher<T> {
|
||||
Cacher {
|
||||
calculation,
|
||||
value: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn value(&mut self, arg: u32) -> u32 {
|
||||
match self.value {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
let v = (self.calculation)(arg);
|
||||
self.value = Some(v);
|
||||
v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ANCHOR: here
|
||||
fn generate_workout(intensity: u32, random_number: u32) {
|
||||
let mut expensive_result = Cacher::new(|num| {
|
||||
println!("calculating slowly...");
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
num
|
||||
});
|
||||
|
||||
if intensity < 25 {
|
||||
println!("Today, do {} pushups!", expensive_result.value(intensity));
|
||||
println!("Next, do {} situps!", expensive_result.value(intensity));
|
||||
} else {
|
||||
if random_number == 3 {
|
||||
println!("Take a break today! Remember to stay hydrated!");
|
||||
} else {
|
||||
println!(
|
||||
"Today, run for {} minutes!",
|
||||
expensive_result.value(intensity)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
|
||||
fn main() {
|
||||
let simulated_user_specified_value = 10;
|
||||
let simulated_random_number = 7;
|
||||
// ANCHOR: here
|
||||
let v1 = vec![1, 2, 3];
|
||||
|
||||
generate_workout(simulated_user_specified_value, simulated_random_number);
|
||||
let v1_iter = v1.iter();
|
||||
|
||||
for val in v1_iter {
|
||||
println!("Got: {}", val);
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "equal-to-x"
|
||||
name = "iterators"
|
||||
version = "0.1.0"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "equal-to-x"
|
||||
name = "iterators"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
fn main() {
|
||||
let x = 4;
|
||||
|
||||
let equal_to_x = |z| z == x;
|
||||
|
||||
let y = 4;
|
||||
|
||||
assert!(equal_to_x(y));
|
||||
}
|
||||
15
listings/ch13-functional-features/listing-13-13/src/lib.rs
Normal file
15
listings/ch13-functional-features/listing-13-13/src/lib.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
// ANCHOR: here
|
||||
#[test]
|
||||
fn iterator_sum() {
|
||||
let v1 = vec![1, 2, 3];
|
||||
|
||||
let v1_iter = v1.iter();
|
||||
|
||||
let total: i32 = v1_iter.sum();
|
||||
|
||||
assert_eq!(total, 6);
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
fn main() {
|
||||
// ANCHOR: here
|
||||
let v1 = vec![1, 2, 3];
|
||||
|
||||
let v1_iter = v1.iter();
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
@@ -1,11 +1,7 @@
|
||||
fn main() {
|
||||
// ANCHOR: here
|
||||
let v1 = vec![1, 2, 3];
|
||||
let v1: Vec<i32> = vec![1, 2, 3];
|
||||
|
||||
let v1_iter = v1.iter();
|
||||
|
||||
for val in v1_iter {
|
||||
println!("Got: {}", val);
|
||||
}
|
||||
v1.iter().map(|x| x + 1);
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ fn main() {
|
||||
// ANCHOR: here
|
||||
let v1: Vec<i32> = vec![1, 2, 3];
|
||||
|
||||
v1.iter().map(|x| x + 1);
|
||||
let v2: Vec<_> = v1.iter().map(|x| x + 1).collect();
|
||||
|
||||
assert_eq!(v2, vec![2, 3, 4]);
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "iterators"
|
||||
name = "shoe_size"
|
||||
version = "0.1.0"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "iterators"
|
||||
name = "shoe_size"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -1,15 +1,48 @@
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct Shoe {
|
||||
size: u32,
|
||||
style: String,
|
||||
}
|
||||
|
||||
fn shoes_in_size(shoes: Vec<Shoe>, shoe_size: u32) -> Vec<Shoe> {
|
||||
shoes.into_iter().filter(|s| s.size == shoe_size).collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
// ANCHOR: here
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn iterator_sum() {
|
||||
let v1 = vec![1, 2, 3];
|
||||
fn filters_by_size() {
|
||||
let shoes = vec![
|
||||
Shoe {
|
||||
size: 10,
|
||||
style: String::from("sneaker"),
|
||||
},
|
||||
Shoe {
|
||||
size: 13,
|
||||
style: String::from("sandal"),
|
||||
},
|
||||
Shoe {
|
||||
size: 10,
|
||||
style: String::from("boot"),
|
||||
},
|
||||
];
|
||||
|
||||
let v1_iter = v1.iter();
|
||||
let in_my_size = shoes_in_size(shoes, 10);
|
||||
|
||||
let total: i32 = v1_iter.sum();
|
||||
|
||||
assert_eq!(total, 6);
|
||||
assert_eq!(
|
||||
in_my_size,
|
||||
vec![
|
||||
Shoe {
|
||||
size: 10,
|
||||
style: String::from("sneaker")
|
||||
},
|
||||
Shoe {
|
||||
size: 10,
|
||||
style: String::from("boot")
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "iterators"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
[package]
|
||||
name = "iterators"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -1,6 +1,6 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "iterators"
|
||||
name = "minigrep"
|
||||
version = "0.1.0"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "iterators"
|
||||
name = "minigrep"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -1,9 +1,23 @@
|
||||
use std::env;
|
||||
use std::process;
|
||||
|
||||
use minigrep::Config;
|
||||
|
||||
// ANCHOR: here
|
||||
fn main() {
|
||||
// ANCHOR: here
|
||||
let v1: Vec<i32> = vec![1, 2, 3];
|
||||
let config = Config::new(env::args()).unwrap_or_else(|err| {
|
||||
eprintln!("Problem parsing arguments: {}", err);
|
||||
process::exit(1);
|
||||
});
|
||||
|
||||
let v2: Vec<_> = v1.iter().map(|x| x + 1).collect();
|
||||
|
||||
assert_eq!(v2, vec![2, 3, 4]);
|
||||
// --snip--
|
||||
// ANCHOR_END: here
|
||||
|
||||
if let Err(e) = minigrep::run(config) {
|
||||
eprintln!("Application error: {}", e);
|
||||
|
||||
process::exit(1);
|
||||
}
|
||||
// ANCHOR: here
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "shoe_size"
|
||||
name = "minigrep"
|
||||
version = "0.1.0"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "shoe_size"
|
||||
name = "minigrep"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -1,11 +1,79 @@
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct Shoe {
|
||||
size: u32,
|
||||
style: String,
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
|
||||
pub struct Config {
|
||||
pub query: String,
|
||||
pub filename: String,
|
||||
pub case_sensitive: bool,
|
||||
}
|
||||
|
||||
fn shoes_in_size(shoes: Vec<Shoe>, shoe_size: u32) -> Vec<Shoe> {
|
||||
shoes.into_iter().filter(|s| s.size == shoe_size).collect()
|
||||
// ANCHOR: here
|
||||
impl Config {
|
||||
pub fn new(
|
||||
mut args: impl Iterator<Item = String>,
|
||||
) -> Result<Config, &'static str> {
|
||||
// --snip--
|
||||
// ANCHOR_END: here
|
||||
if args.len() < 3 {
|
||||
return Err("not enough arguments");
|
||||
}
|
||||
|
||||
let query = args[1].clone();
|
||||
let filename = args[2].clone();
|
||||
|
||||
let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
|
||||
|
||||
Ok(Config {
|
||||
query,
|
||||
filename,
|
||||
case_sensitive,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
|
||||
let contents = fs::read_to_string(config.filename)?;
|
||||
|
||||
let results = if config.case_sensitive {
|
||||
search(&config.query, &contents)
|
||||
} else {
|
||||
search_case_insensitive(&config.query, &contents)
|
||||
};
|
||||
|
||||
for line in results {
|
||||
println!("{}", line);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
let mut results = Vec::new();
|
||||
|
||||
for line in contents.lines() {
|
||||
if line.contains(query) {
|
||||
results.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
pub fn search_case_insensitive<'a>(
|
||||
query: &str,
|
||||
contents: &'a str,
|
||||
) -> Vec<&'a str> {
|
||||
let query = query.to_lowercase();
|
||||
let mut results = Vec::new();
|
||||
|
||||
for line in contents.lines() {
|
||||
if line.to_lowercase().contains(&query) {
|
||||
results.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -13,36 +81,29 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn filters_by_size() {
|
||||
let shoes = vec![
|
||||
Shoe {
|
||||
size: 10,
|
||||
style: String::from("sneaker"),
|
||||
},
|
||||
Shoe {
|
||||
size: 13,
|
||||
style: String::from("sandal"),
|
||||
},
|
||||
Shoe {
|
||||
size: 10,
|
||||
style: String::from("boot"),
|
||||
},
|
||||
];
|
||||
fn case_sensitive() {
|
||||
let query = "duct";
|
||||
let contents = "\
|
||||
Rust:
|
||||
safe, fast, productive.
|
||||
Pick three.
|
||||
Duct tape.";
|
||||
|
||||
let in_my_size = shoes_in_size(shoes, 10);
|
||||
assert_eq!(vec!["safe, fast, productive."], search(query, contents));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn case_insensitive() {
|
||||
let query = "rUsT";
|
||||
let contents = "\
|
||||
Rust:
|
||||
safe, fast, productive.
|
||||
Pick three.
|
||||
Trust me.";
|
||||
|
||||
assert_eq!(
|
||||
in_my_size,
|
||||
vec![
|
||||
Shoe {
|
||||
size: 10,
|
||||
style: String::from("sneaker")
|
||||
},
|
||||
Shoe {
|
||||
size: 10,
|
||||
style: String::from("boot")
|
||||
},
|
||||
]
|
||||
vec!["Rust:", "Trust me."],
|
||||
search_case_insensitive(query, contents)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "counter"
|
||||
name = "minigrep"
|
||||
version = "0.1.0"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "counter"
|
||||
name = "minigrep"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -1,9 +1,113 @@
|
||||
struct Counter {
|
||||
count: u32,
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
|
||||
pub struct Config {
|
||||
pub query: String,
|
||||
pub filename: String,
|
||||
pub case_sensitive: bool,
|
||||
}
|
||||
|
||||
impl Counter {
|
||||
fn new() -> Counter {
|
||||
Counter { count: 0 }
|
||||
// ANCHOR: here
|
||||
impl Config {
|
||||
pub fn new(
|
||||
mut args: impl Iterator<Item = String>,
|
||||
) -> Result<Config, &'static str> {
|
||||
args.next();
|
||||
|
||||
let query = match args.next() {
|
||||
Some(arg) => arg,
|
||||
None => return Err("Didn't get a query string"),
|
||||
};
|
||||
|
||||
let filename = match args.next() {
|
||||
Some(arg) => arg,
|
||||
None => return Err("Didn't get a file name"),
|
||||
};
|
||||
|
||||
let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
|
||||
|
||||
Ok(Config {
|
||||
query,
|
||||
filename,
|
||||
case_sensitive,
|
||||
})
|
||||
}
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
|
||||
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
|
||||
let contents = fs::read_to_string(config.filename)?;
|
||||
|
||||
let results = if config.case_sensitive {
|
||||
search(&config.query, &contents)
|
||||
} else {
|
||||
search_case_insensitive(&config.query, &contents)
|
||||
};
|
||||
|
||||
for line in results {
|
||||
println!("{}", line);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
let mut results = Vec::new();
|
||||
|
||||
for line in contents.lines() {
|
||||
if line.contains(query) {
|
||||
results.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
pub fn search_case_insensitive<'a>(
|
||||
query: &str,
|
||||
contents: &'a str,
|
||||
) -> Vec<&'a str> {
|
||||
let query = query.to_lowercase();
|
||||
let mut results = Vec::new();
|
||||
|
||||
for line in contents.lines() {
|
||||
if line.to_lowercase().contains(&query) {
|
||||
results.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn case_sensitive() {
|
||||
let query = "duct";
|
||||
let contents = "\
|
||||
Rust:
|
||||
safe, fast, productive.
|
||||
Pick three.
|
||||
Duct tape.";
|
||||
|
||||
assert_eq!(vec!["safe, fast, productive."], search(query, contents));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn case_insensitive() {
|
||||
let query = "rUsT";
|
||||
let contents = "\
|
||||
Rust:
|
||||
safe, fast, productive.
|
||||
Pick three.
|
||||
Trust me.";
|
||||
|
||||
assert_eq!(
|
||||
vec!["Rust:", "Trust me."],
|
||||
search_case_insensitive(query, contents)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
struct Counter {
|
||||
count: u32,
|
||||
}
|
||||
|
||||
impl Counter {
|
||||
fn new() -> Counter {
|
||||
Counter { count: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
// ANCHOR: here
|
||||
impl Iterator for Counter {
|
||||
type Item = u32;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.count < 5 {
|
||||
self.count += 1;
|
||||
Some(self.count)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
@@ -1,6 +1,6 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "counter"
|
||||
name = "minigrep"
|
||||
version = "0.1.0"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "counter"
|
||||
name = "minigrep"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -1,41 +1,108 @@
|
||||
struct Counter {
|
||||
count: u32,
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
|
||||
pub struct Config {
|
||||
pub query: String,
|
||||
pub filename: String,
|
||||
pub case_sensitive: bool,
|
||||
}
|
||||
|
||||
impl Counter {
|
||||
fn new() -> Counter {
|
||||
Counter { count: 0 }
|
||||
impl Config {
|
||||
pub fn new(
|
||||
mut args: impl Iterator<Item = String>,
|
||||
) -> Result<Config, &'static str> {
|
||||
args.next();
|
||||
|
||||
let query = match args.next() {
|
||||
Some(arg) => arg,
|
||||
None => return Err("Didn't get a query string"),
|
||||
};
|
||||
|
||||
let filename = match args.next() {
|
||||
Some(arg) => arg,
|
||||
None => return Err("Didn't get a file name"),
|
||||
};
|
||||
|
||||
let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
|
||||
|
||||
Ok(Config {
|
||||
query,
|
||||
filename,
|
||||
case_sensitive,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Counter {
|
||||
type Item = u32;
|
||||
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
|
||||
let contents = fs::read_to_string(config.filename)?;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.count < 5 {
|
||||
self.count += 1;
|
||||
Some(self.count)
|
||||
} else {
|
||||
None
|
||||
let results = if config.case_sensitive {
|
||||
search(&config.query, &contents)
|
||||
} else {
|
||||
search_case_insensitive(&config.query, &contents)
|
||||
};
|
||||
|
||||
for line in results {
|
||||
println!("{}", line);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ANCHOR: here
|
||||
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
contents
|
||||
.lines()
|
||||
.filter(|line| line.contains(query))
|
||||
.collect()
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
|
||||
pub fn search_case_insensitive<'a>(
|
||||
query: &str,
|
||||
contents: &'a str,
|
||||
) -> Vec<&'a str> {
|
||||
let query = query.to_lowercase();
|
||||
let mut results = Vec::new();
|
||||
|
||||
for line in contents.lines() {
|
||||
if line.to_lowercase().contains(&query) {
|
||||
results.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// ANCHOR: here
|
||||
#[test]
|
||||
fn calling_next_directly() {
|
||||
let mut counter = Counter::new();
|
||||
fn case_sensitive() {
|
||||
let query = "duct";
|
||||
let contents = "\
|
||||
Rust:
|
||||
safe, fast, productive.
|
||||
Pick three.
|
||||
Duct tape.";
|
||||
|
||||
assert_eq!(counter.next(), Some(1));
|
||||
assert_eq!(counter.next(), Some(2));
|
||||
assert_eq!(counter.next(), Some(3));
|
||||
assert_eq!(counter.next(), Some(4));
|
||||
assert_eq!(counter.next(), Some(5));
|
||||
assert_eq!(counter.next(), None);
|
||||
assert_eq!(vec!["safe, fast, productive."], search(query, contents));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn case_insensitive() {
|
||||
let query = "rUsT";
|
||||
let contents = "\
|
||||
Rust:
|
||||
safe, fast, productive.
|
||||
Pick three.
|
||||
Trust me.";
|
||||
|
||||
assert_eq!(
|
||||
vec!["Rust:", "Trust me."],
|
||||
search_case_insensitive(query, contents)
|
||||
);
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "counter"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
[package]
|
||||
name = "counter"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -1,51 +0,0 @@
|
||||
struct Counter {
|
||||
count: u32,
|
||||
}
|
||||
|
||||
impl Counter {
|
||||
fn new() -> Counter {
|
||||
Counter { count: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Counter {
|
||||
type Item = u32;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.count < 5 {
|
||||
self.count += 1;
|
||||
Some(self.count)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn calling_next_directly() {
|
||||
let mut counter = Counter::new();
|
||||
|
||||
assert_eq!(counter.next(), Some(1));
|
||||
assert_eq!(counter.next(), Some(2));
|
||||
assert_eq!(counter.next(), Some(3));
|
||||
assert_eq!(counter.next(), Some(4));
|
||||
assert_eq!(counter.next(), Some(5));
|
||||
assert_eq!(counter.next(), None);
|
||||
}
|
||||
|
||||
// ANCHOR: here
|
||||
#[test]
|
||||
fn using_other_iterator_trait_methods() {
|
||||
let sum: u32 = Counter::new()
|
||||
.zip(Counter::new().skip(1))
|
||||
.map(|(a, b)| a * b)
|
||||
.filter(|x| x % 3 == 0)
|
||||
.sum();
|
||||
assert_eq!(18, sum);
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "minigrep"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
[package]
|
||||
name = "minigrep"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -1,23 +0,0 @@
|
||||
use std::env;
|
||||
use std::process;
|
||||
|
||||
use minigrep::Config;
|
||||
|
||||
// ANCHOR: here
|
||||
fn main() {
|
||||
let config = Config::new(env::args()).unwrap_or_else(|err| {
|
||||
eprintln!("Problem parsing arguments: {}", err);
|
||||
process::exit(1);
|
||||
});
|
||||
|
||||
// --snip--
|
||||
// ANCHOR_END: here
|
||||
|
||||
if let Err(e) = minigrep::run(config) {
|
||||
eprintln!("Application error: {}", e);
|
||||
|
||||
process::exit(1);
|
||||
}
|
||||
// ANCHOR: here
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
@@ -1,6 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "minigrep"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
[package]
|
||||
name = "minigrep"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -1,107 +0,0 @@
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
|
||||
pub struct Config {
|
||||
pub query: String,
|
||||
pub filename: String,
|
||||
pub case_sensitive: bool,
|
||||
}
|
||||
|
||||
// ANCHOR: here
|
||||
impl Config {
|
||||
pub fn new(mut args: env::Args) -> Result<Config, &'static str> {
|
||||
// --snip--
|
||||
// ANCHOR_END: here
|
||||
if args.len() < 3 {
|
||||
return Err("not enough arguments");
|
||||
}
|
||||
|
||||
let query = args[1].clone();
|
||||
let filename = args[2].clone();
|
||||
|
||||
let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
|
||||
|
||||
Ok(Config {
|
||||
query,
|
||||
filename,
|
||||
case_sensitive,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
|
||||
let contents = fs::read_to_string(config.filename)?;
|
||||
|
||||
let results = if config.case_sensitive {
|
||||
search(&config.query, &contents)
|
||||
} else {
|
||||
search_case_insensitive(&config.query, &contents)
|
||||
};
|
||||
|
||||
for line in results {
|
||||
println!("{}", line);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
let mut results = Vec::new();
|
||||
|
||||
for line in contents.lines() {
|
||||
if line.contains(query) {
|
||||
results.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
pub fn search_case_insensitive<'a>(
|
||||
query: &str,
|
||||
contents: &'a str,
|
||||
) -> Vec<&'a str> {
|
||||
let query = query.to_lowercase();
|
||||
let mut results = Vec::new();
|
||||
|
||||
for line in contents.lines() {
|
||||
if line.to_lowercase().contains(&query) {
|
||||
results.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn case_sensitive() {
|
||||
let query = "duct";
|
||||
let contents = "\
|
||||
Rust:
|
||||
safe, fast, productive.
|
||||
Pick three.
|
||||
Duct tape.";
|
||||
|
||||
assert_eq!(vec!["safe, fast, productive."], search(query, contents));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn case_insensitive() {
|
||||
let query = "rUsT";
|
||||
let contents = "\
|
||||
Rust:
|
||||
safe, fast, productive.
|
||||
Pick three.
|
||||
Trust me.";
|
||||
|
||||
assert_eq!(
|
||||
vec!["Rust:", "Trust me."],
|
||||
search_case_insensitive(query, contents)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "minigrep"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
[package]
|
||||
name = "minigrep"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -1,111 +0,0 @@
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
|
||||
pub struct Config {
|
||||
pub query: String,
|
||||
pub filename: String,
|
||||
pub case_sensitive: bool,
|
||||
}
|
||||
|
||||
// ANCHOR: here
|
||||
impl Config {
|
||||
pub fn new(mut args: env::Args) -> Result<Config, &'static str> {
|
||||
args.next();
|
||||
|
||||
let query = match args.next() {
|
||||
Some(arg) => arg,
|
||||
None => return Err("Didn't get a query string"),
|
||||
};
|
||||
|
||||
let filename = match args.next() {
|
||||
Some(arg) => arg,
|
||||
None => return Err("Didn't get a file name"),
|
||||
};
|
||||
|
||||
let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
|
||||
|
||||
Ok(Config {
|
||||
query,
|
||||
filename,
|
||||
case_sensitive,
|
||||
})
|
||||
}
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
|
||||
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
|
||||
let contents = fs::read_to_string(config.filename)?;
|
||||
|
||||
let results = if config.case_sensitive {
|
||||
search(&config.query, &contents)
|
||||
} else {
|
||||
search_case_insensitive(&config.query, &contents)
|
||||
};
|
||||
|
||||
for line in results {
|
||||
println!("{}", line);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
let mut results = Vec::new();
|
||||
|
||||
for line in contents.lines() {
|
||||
if line.contains(query) {
|
||||
results.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
pub fn search_case_insensitive<'a>(
|
||||
query: &str,
|
||||
contents: &'a str,
|
||||
) -> Vec<&'a str> {
|
||||
let query = query.to_lowercase();
|
||||
let mut results = Vec::new();
|
||||
|
||||
for line in contents.lines() {
|
||||
if line.to_lowercase().contains(&query) {
|
||||
results.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn case_sensitive() {
|
||||
let query = "duct";
|
||||
let contents = "\
|
||||
Rust:
|
||||
safe, fast, productive.
|
||||
Pick three.
|
||||
Duct tape.";
|
||||
|
||||
assert_eq!(vec!["safe, fast, productive."], search(query, contents));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn case_insensitive() {
|
||||
let query = "rUsT";
|
||||
let contents = "\
|
||||
Rust:
|
||||
safe, fast, productive.
|
||||
Pick three.
|
||||
Trust me.";
|
||||
|
||||
assert_eq!(
|
||||
vec!["Rust:", "Trust me."],
|
||||
search_case_insensitive(query, contents)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "minigrep"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
[package]
|
||||
name = "minigrep"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -1,106 +0,0 @@
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
|
||||
pub struct Config {
|
||||
pub query: String,
|
||||
pub filename: String,
|
||||
pub case_sensitive: bool,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new(mut args: std::env::Args) -> Result<Config, &'static str> {
|
||||
args.next();
|
||||
|
||||
let query = match args.next() {
|
||||
Some(arg) => arg,
|
||||
None => return Err("Didn't get a query string"),
|
||||
};
|
||||
|
||||
let filename = match args.next() {
|
||||
Some(arg) => arg,
|
||||
None => return Err("Didn't get a file name"),
|
||||
};
|
||||
|
||||
let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
|
||||
|
||||
Ok(Config {
|
||||
query,
|
||||
filename,
|
||||
case_sensitive,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
|
||||
let contents = fs::read_to_string(config.filename)?;
|
||||
|
||||
let results = if config.case_sensitive {
|
||||
search(&config.query, &contents)
|
||||
} else {
|
||||
search_case_insensitive(&config.query, &contents)
|
||||
};
|
||||
|
||||
for line in results {
|
||||
println!("{}", line);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ANCHOR: here
|
||||
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
contents
|
||||
.lines()
|
||||
.filter(|line| line.contains(query))
|
||||
.collect()
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
|
||||
pub fn search_case_insensitive<'a>(
|
||||
query: &str,
|
||||
contents: &'a str,
|
||||
) -> Vec<&'a str> {
|
||||
let query = query.to_lowercase();
|
||||
let mut results = Vec::new();
|
||||
|
||||
for line in contents.lines() {
|
||||
if line.to_lowercase().contains(&query) {
|
||||
results.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn case_sensitive() {
|
||||
let query = "duct";
|
||||
let contents = "\
|
||||
Rust:
|
||||
safe, fast, productive.
|
||||
Pick three.
|
||||
Duct tape.";
|
||||
|
||||
assert_eq!(vec!["safe, fast, productive."], search(query, contents));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn case_insensitive() {
|
||||
let query = "rUsT";
|
||||
let contents = "\
|
||||
Rust:
|
||||
safe, fast, productive.
|
||||
Pick three.
|
||||
Trust me.";
|
||||
|
||||
assert_eq!(
|
||||
vec!["Rust:", "Trust me."],
|
||||
search_case_insensitive(query, contents)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "cacher"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
[package]
|
||||
name = "cacher"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -1,23 +0,0 @@
|
||||
$ cargo test
|
||||
Compiling cacher v0.1.0 (file:///projects/cacher)
|
||||
Finished test [unoptimized + debuginfo] target(s) in 0.72s
|
||||
Running unittests (target/debug/deps/cacher-074d7c200c000afa)
|
||||
|
||||
running 1 test
|
||||
test tests::call_with_different_values ... FAILED
|
||||
|
||||
failures:
|
||||
|
||||
---- tests::call_with_different_values stdout ----
|
||||
thread 'main' panicked at 'assertion failed: `(left == right)`
|
||||
left: `1`,
|
||||
right: `2`', src/lib.rs:43:9
|
||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||
|
||||
|
||||
failures:
|
||||
tests::call_with_different_values
|
||||
|
||||
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
|
||||
|
||||
error: test failed, to rerun pass '--lib'
|
||||
@@ -1,47 +0,0 @@
|
||||
struct Cacher<T>
|
||||
where
|
||||
T: Fn(u32) -> u32,
|
||||
{
|
||||
calculation: T,
|
||||
value: Option<u32>,
|
||||
}
|
||||
|
||||
impl<T> Cacher<T>
|
||||
where
|
||||
T: Fn(u32) -> u32,
|
||||
{
|
||||
fn new(calculation: T) -> Cacher<T> {
|
||||
Cacher {
|
||||
calculation,
|
||||
value: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn value(&mut self, arg: u32) -> u32 {
|
||||
match self.value {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
let v = (self.calculation)(arg);
|
||||
self.value = Some(v);
|
||||
v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// ANCHOR: here
|
||||
#[test]
|
||||
fn call_with_different_values() {
|
||||
let mut c = Cacher::new(|a| a);
|
||||
|
||||
let v1 = c.value(1);
|
||||
let v2 = c.value(2);
|
||||
|
||||
assert_eq!(v2, 2);
|
||||
}
|
||||
// ANCHOR_END: here
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "equal-to-x"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
[package]
|
||||
name = "equal-to-x"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -1,12 +0,0 @@
|
||||
$ cargo run
|
||||
Compiling equal-to-x v0.1.0 (file:///projects/equal-to-x)
|
||||
error[E0434]: can't capture dynamic environment in a fn item
|
||||
--> src/main.rs:5:14
|
||||
|
|
||||
5 | z == x
|
||||
| ^
|
||||
|
|
||||
= help: use the `|| { ... }` closure form instead
|
||||
|
||||
For more information about this error, try `rustc --explain E0434`.
|
||||
error: could not compile `equal-to-x` due to previous error
|
||||
@@ -1,11 +0,0 @@
|
||||
fn main() {
|
||||
let x = 4;
|
||||
|
||||
fn equal_to_x(z: i32) -> bool {
|
||||
z == x
|
||||
}
|
||||
|
||||
let y = 4;
|
||||
|
||||
assert!(equal_to_x(y));
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "equal-to-x"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
[package]
|
||||
name = "equal-to-x"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -1,20 +0,0 @@
|
||||
$ cargo run
|
||||
Compiling equal-to-x v0.1.0 (file:///projects/equal-to-x)
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> src/main.rs:6:40
|
||||
|
|
||||
2 | let x = vec![1, 2, 3];
|
||||
| - move occurs because `x` has type `Vec<i32>`, which does not implement the `Copy` trait
|
||||
3 |
|
||||
4 | let equal_to_x = move |z| z == x;
|
||||
| -------- - variable moved due to use in closure
|
||||
| |
|
||||
| value moved into closure here
|
||||
5 |
|
||||
6 | println!("can't use x here: {:?}", x);
|
||||
| ^ value borrowed here after move
|
||||
|
|
||||
= note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
||||
error: could not compile `equal-to-x` due to previous error
|
||||
@@ -1,11 +0,0 @@
|
||||
fn main() {
|
||||
let x = vec![1, 2, 3];
|
||||
|
||||
let equal_to_x = move |z| z == x;
|
||||
|
||||
println!("can't use x here: {:?}", x);
|
||||
|
||||
let y = vec![1, 2, 3];
|
||||
|
||||
assert!(equal_to_x(y));
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "counter"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
[package]
|
||||
name = "counter"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user