Skip to content

Commit 2a41387

Browse files
committed
chore: initial commit
0 parents  commit 2a41387

File tree

59 files changed

+3655
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+3655
-0
lines changed

Diff for: .gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
target

Diff for: README.md

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# The Rust Programming Language
2+
3+
Book to get started with the Rust programming language.
4+
5+
Available online: <https://doc.rust-lang.org/book/>
6+
7+
Available offline: `rustup docs --book`
8+
9+
## About
10+
11+
Rust is a multi-paradigm, general-purpose programming language. Rust emphasizes performance, type safety, and concurrency. Rust enforces memory safety—that is, that all references point to valid memory—without requiring the use of a garbage collector or reference counting present in other memory-safe languages.
12+
13+
Rust keeps track of who can read and write to memory. It knows when the program is using memory and immediately frees the memory once it is no longer needed.
14+
15+
- [Website](https://www.rust-lang.org/)
16+
- Local Documentation: `rustup doc`
17+
- Rust version used: v1.74.0 (`rustc --version`)
18+
19+
## Summary
20+
21+
1. [Getting Started](./chapter_1_getting_started)
22+
2. [Programming a Guessing Game](./chapter_2_guessing_game)
23+
3. [Common Programming Concepts](./chapter_3_common_concepts)
24+
4. [Understanding Ownership](./chapter_4_ownership)
25+
5. [Using Structs to Structure Related Data](./chapter_5_structs)
26+
6. [Enums and Pattern Matching](./chapter_6_enums)
27+
7. [Managing Growing Projects with Packages, Crates, and Modules](./chapter_7_packages_crates_modules)
28+
8. [Common Collections](./chapter_8_common_collections)
29+
9. [Error Handling](./chapter_9_error_handling)
30+
10. [Generic Types, Traits, and Lifetimes](./chapter_10_generics_traits_lifetimes)
31+
11. [Testing](./chapter_11_testing)
32+
12. [An I/O Project: Building a Command Line Program: `minigrep`](./chapter_12_minigrep)
33+
13. [Functional Language Features: Iterators and Closures](./chapter_13_iterators_and_closures)

Diff for: chapter_10_generics_traits_lifetimes/Cargo.lock

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: chapter_10_generics_traits_lifetimes/Cargo.toml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "chapter_10_generics_traits_lifetimes"
3+
version = "1.0.0"
4+
edition = "2021"
5+
6+
[dependencies]

Diff for: chapter_10_generics_traits_lifetimes/src/main.rs

+241
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
use std::fmt::{Debug, Display};
2+
3+
// Disable warnings for learning purposes and avoid useless `println!` usage only to use a variable
4+
#[allow(unused_variables)]
5+
#[allow(dead_code)]
6+
#[allow(unused_assignments)]
7+
#[allow(unused_mut)]
8+
#[allow(unreachable_code)]
9+
10+
fn main() {
11+
/* Generic Types, Traits, and Lifetimes */
12+
13+
/* Generic Data Types */
14+
// Function signatures or structs, that can use many different concrete data types.
15+
16+
// Generic type parameters in `fn` definitions
17+
fn largest<T: PartialOrd>(list: &[T]) -> &T {
18+
let mut largest = &list[0];
19+
for item in list {
20+
// Error: `>` cannot be applied to type `T`
21+
// Solution: `PartialOrd` trait (only use types whose values can be ordered)
22+
if item > largest {
23+
largest = item;
24+
}
25+
}
26+
largest
27+
}
28+
let number_list = vec![34, 50, 25, 100, 65];
29+
let result = largest(&number_list);
30+
println!("The largest number is {}", result);
31+
32+
let char_list = vec!['y', 'm', 'a', 'q'];
33+
let result = largest(&char_list);
34+
println!("The largest char is {}", result);
35+
36+
// Generic type parameters in `struct` definitions
37+
struct Point<T> {
38+
x: T,
39+
y: T,
40+
}
41+
let integer = Point { x: 5, y: 10 };
42+
let float = Point { x: 1.0, y: 4.0 };
43+
44+
// We can use different concrete types for each generic type parameter
45+
struct Point2<T, U> {
46+
x: T,
47+
y: U,
48+
}
49+
let both_integer = Point2 { x: 5, y: 10 };
50+
let both_float = Point2 { x: 1.0, y: 4.0 };
51+
let integer_and_float = Point2 { x: 5, y: 4.0 };
52+
53+
// Generic type parameters in `enum` definitions
54+
enum Option<T> {
55+
Some(T),
56+
None,
57+
}
58+
59+
// Generic type parameters in `impl` blocks
60+
impl<T> Point<T> {
61+
fn x(&self) -> &T {
62+
&self.x
63+
}
64+
}
65+
let point = Point { x: 5, y: 10 };
66+
println!("p.x = {}", point.x());
67+
68+
// We can also specify constraints on generic types when defining methods on the type. We could, for example, implement methods only on `Point<f32>` instances rather than on `Point<T>` instances.
69+
impl Point<f32> {
70+
fn distance_from_origin(&self) -> f32 {
71+
(self.x.powi(2) + self.y.powi(2)).sqrt()
72+
}
73+
}
74+
75+
/* Traits: Defining Shared Behavior */
76+
// Defines functionality a particular type has and can share with other types.
77+
// We can use trait bounds to specify that a generic type can be any type that has certain behavior.
78+
// Similar to interfaces in other languages.
79+
80+
// Defining a Trait (using `trait`)
81+
/* Example:
82+
We have multiple structs that hold various kinds and amounts of text: a `NewsArticle` struct that holds a news story filed in a particular location and a `Tweet` that can have at most 140 characters along with metadata like whether it was a retweet or a reply to another tweet.
83+
84+
We want to make a media aggregator library crate named `aggregator` that can display summaries of data that might be stored in a `NewsArticle` or `Tweet` instance.
85+
*/
86+
pub trait Summary {
87+
fn summarize(&self) -> String;
88+
}
89+
90+
// Implementing a Trait on a Type (using 'for`)
91+
pub struct NewsArticle {
92+
pub headline: String,
93+
pub location: String,
94+
pub author: String,
95+
pub content: String,
96+
}
97+
impl Summary for NewsArticle {
98+
fn summarize(&self) -> String {
99+
format!("{}, by {} ({})", self.headline, self.author, self.location)
100+
}
101+
}
102+
103+
pub struct Tweet {
104+
pub username: String,
105+
pub content: String,
106+
pub reply: bool,
107+
pub retweet: bool,
108+
}
109+
impl Summary for Tweet {
110+
fn summarize(&self) -> String {
111+
format!("{}: {}", self.username, self.content)
112+
}
113+
}
114+
let tweet = Tweet {
115+
username: String::from("horse_ebooks"),
116+
content: String::from("of course, as you probably already know, people"),
117+
reply: false,
118+
retweet: false,
119+
};
120+
println!("1 new tweet: {}", tweet.summarize());
121+
122+
/* Restriction: We can implement a trait on a type only if at least one of the trait or the type is local to our crate (coherence, and more specifically the orphan rule).
123+
124+
Examples:
125+
- We can implement standard library traits like `Display` on a custom type like `Tweet`.
126+
- We can also implement `Summary` on `Vec<T>`.
127+
- We can't implement external traits on external types. For example, we can't implement the `Display` trait on `Vec<T>` (both defined in the standard library).
128+
*/
129+
130+
// Default Implementations
131+
pub trait SummaryWithDefault {
132+
fn summarize(&self) -> String {
133+
String::from("(Read more...)")
134+
}
135+
}
136+
137+
// Traits as Parameters (using `impl Trait`)
138+
pub fn notify(item: &impl Summary) {
139+
println!("Breaking news! {}", item.summarize());
140+
}
141+
142+
// Trait Bound Syntax
143+
// The `impl Trait` syntax works for straightforward cases but is actually syntax sugar for a longer form known as a trait bound.
144+
pub fn notify_trait_bound<T: Summary>(item: &T) {
145+
println!("Breaking news! {}", item.summarize());
146+
}
147+
// Trait bounds can express more complexity in others cases than `impl Trait` syntax.
148+
// Example:
149+
pub fn notify_verbose(item1: &impl Summary, item2: &impl Summary) {}
150+
// vs
151+
pub fn notify_trait_bound_verbose<T: Summary>(item1: &T, item2: &T) {}
152+
153+
// Specifying Multiple Trait Bounds with the `+` Syntax
154+
pub fn notify_multiple(item: &(impl Summary + Display)) {}
155+
156+
// Also valid with trait bounds
157+
pub fn notify_trait_bound_multiple<T: Summary + Display>(item: &T) {}
158+
159+
// Clearer Trait Bounds with `where` Clauses
160+
fn some_function_verbose<T: Display + Clone, U: Clone + Debug>(t: &T, u: &U) -> i32 {
161+
0
162+
}
163+
// vs
164+
fn some_function<T, U>(t: &T, u: &U) -> i32
165+
where
166+
T: Display + Clone,
167+
U: Clone + Debug,
168+
{
169+
0
170+
}
171+
172+
// Returning Types that Implement Traits
173+
// Restriction: We can only return a single type. Example: we can't return a `NewsArticle` and a `Tweet` in the same function (even if both implements `Summary`). There is a way to do that covered in Chapter 17.
174+
fn returns_summarizable() -> impl Summary {
175+
Tweet {
176+
username: String::from("horse_ebooks"),
177+
content: String::from("of course, as you probably already know, people"),
178+
reply: false,
179+
retweet: false,
180+
}
181+
}
182+
183+
// Using Trait Bounds to Conditionally Implement Methods
184+
// Example:
185+
struct Pair<T> {
186+
x: T,
187+
y: T,
188+
}
189+
impl<T> Pair<T> {
190+
fn new(x: T, y: T) -> Self {
191+
Self { x, y }
192+
}
193+
}
194+
impl<T: Display + PartialOrd> Pair<T> {
195+
fn compare_display(&self) {
196+
if self.x >= self.y {
197+
println!("The largest member is x = {}.", self.x);
198+
} else {
199+
println!("The largest member is y = {}.", self.y);
200+
}
201+
}
202+
}
203+
204+
/* Validating References with Lifetimes */
205+
// Lifetimes are another kind of generic.
206+
// Rather than ensuring that a type has the behavior we want, lifetimes ensure that references are valid as long as we need them to be.
207+
// Every reference in Rust has a lifetime, which is the scope for which that reference is valid.
208+
209+
// Preventing Dangling References with Lifetimes
210+
let result;
211+
{
212+
let x = 5;
213+
result = &x;
214+
}
215+
// println!("result: {}", result); // error: `x` does not live long enough (once `x` goes out of scope, it will be deallocated and the memory will be invalid)
216+
217+
// Generic Lifetimes in Functions
218+
// Lifetime Annotation Syntax
219+
// Lifetime annotations don't change how long any of the references live.
220+
// Rather, they describe the relationships of the lifetimes of multiple references to each other without affecting the lifetimes.
221+
222+
// &i32 // a reference
223+
// &'a i32 // a reference with an explicit lifetime
224+
// &'a mut i32 // a mutable reference with an explicit lifetime
225+
226+
// Example: Function that returns the longest of two string slices.
227+
// Signature express the following constraint:
228+
// The returned reference will be valid as long as both the parameters are valid.
229+
// => string slices that live at least as long as lifetime `'a`.
230+
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
231+
if x.len() > y.len() {
232+
x
233+
} else {
234+
y
235+
}
236+
}
237+
let string1 = String::from("abcd");
238+
let string2 = "xyz";
239+
let result = longest(&string1, string2);
240+
println!("The longest string is \"{}\".", result);
241+
}

0 commit comments

Comments
 (0)