You've already forked comprehensive-rust
mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-06-22 16:57:41 +02:00
Publish Comprehensive Rust 🦀
This commit is contained in:
21
src/generics/closures.md
Normal file
21
src/generics/closures.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Closures
|
||||
|
||||
Closures or lambda expressions have types which cannot be named. However, they
|
||||
implement special [`Fn`](https://doc.rust-lang.org/std/ops/trait.Fn.html),
|
||||
[`FnMut`](https://doc.rust-lang.org/std/ops/trait.FnMut.html), and
|
||||
[`FnOnce`](https://doc.rust-lang.org/std/ops/trait.FnOnce.html) traits:
|
||||
|
||||
```rust,editable
|
||||
fn apply_with_log(func: impl FnOnce(i32) -> i32, input: i32) -> i32 {
|
||||
println!("Calling function on {input}");
|
||||
func(input)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let add_3 = |x| x + 3;
|
||||
let mul_5 = |x| x * 5;
|
||||
|
||||
println!("add_3: {}", apply_with_log(add_3, 10));
|
||||
println!("mul_5: {}", apply_with_log(mul_5, 20));
|
||||
}
|
||||
```
|
17
src/generics/data-types.md
Normal file
17
src/generics/data-types.md
Normal file
@ -0,0 +1,17 @@
|
||||
# Generic Data Types
|
||||
|
||||
You can use generics to abstract over the concrete field type:
|
||||
|
||||
```rust,editable
|
||||
#[derive(Debug)]
|
||||
struct Point<T> {
|
||||
x: T,
|
||||
y: T,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let integer = Point { x: 5, y: 10 };
|
||||
let float = Point { x: 1.0, y: 4.0 };
|
||||
println!("{integer:?} and {float:?}");
|
||||
}
|
||||
```
|
20
src/generics/impl-trait.md
Normal file
20
src/generics/impl-trait.md
Normal file
@ -0,0 +1,20 @@
|
||||
# `impl Trait`
|
||||
|
||||
Similar to trait bounds, an `impl Trait` syntax can be used in function
|
||||
arguments and return values:
|
||||
|
||||
```rust,editable
|
||||
use std::fmt::Display;
|
||||
|
||||
fn get_x(name: impl Display) -> impl Display {
|
||||
format!("Hello {name}")
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = get_x("foo");
|
||||
println!("{x}");
|
||||
}
|
||||
```
|
||||
|
||||
* `impl Trait` cannot be used with the `::<>` turbo fish syntax.
|
||||
* `impl Trait` allows you to work with types which you cannot name.
|
21
src/generics/methods.md
Normal file
21
src/generics/methods.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Generic Methods
|
||||
|
||||
You can declare a generic type on your `impl` block:
|
||||
|
||||
```rust,editable
|
||||
#[derive(Debug)]
|
||||
struct Point<T>(T, T);
|
||||
|
||||
impl<T> Point<T> {
|
||||
fn x(&self) -> &T {
|
||||
&self.0 // + 10
|
||||
}
|
||||
|
||||
// fn set_x(&mut self, x: T)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let p = Point(5, 10);
|
||||
println!("p.x = {}", p.x());
|
||||
}
|
||||
```
|
32
src/generics/monomorphization.md
Normal file
32
src/generics/monomorphization.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Monomorphization
|
||||
|
||||
Generic code is turned into non-generic code based on the call sites:
|
||||
|
||||
```rust,editable
|
||||
fn main() {
|
||||
let integer = Some(5);
|
||||
let float = Some(5.0);
|
||||
}
|
||||
```
|
||||
|
||||
behaves as if you wrote
|
||||
|
||||
```rust,editable
|
||||
enum Option_i32 {
|
||||
Some(i32),
|
||||
None,
|
||||
}
|
||||
|
||||
enum Option_f64 {
|
||||
Some(f64),
|
||||
None,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let integer = Option_i32::Some(5);
|
||||
let float = Option_f64::Some(5.0);
|
||||
}
|
||||
```
|
||||
|
||||
This is a zero-cost abstraction: you get exactly the same result as if you had
|
||||
hand-coded the data structures without the abstraction.
|
17
src/generics/trait-bounds.md
Normal file
17
src/generics/trait-bounds.md
Normal file
@ -0,0 +1,17 @@
|
||||
# Trait Bounds
|
||||
|
||||
When working with generics, you often want to limit the types. You can do this
|
||||
with `T: Trait` or `impl Trait`:
|
||||
|
||||
```rust,editable
|
||||
fn duplicate<T: Clone>(a: T) -> (T, T) {
|
||||
(a.clone(), a.clone())
|
||||
}
|
||||
|
||||
// struct NotClonable;
|
||||
|
||||
fn main() {
|
||||
let foo = String::from("foo");
|
||||
let pair = duplicate(foo);
|
||||
}
|
||||
```
|
86
src/generics/trait-objects.md
Normal file
86
src/generics/trait-objects.md
Normal file
@ -0,0 +1,86 @@
|
||||
# Trait Objects
|
||||
|
||||
We've seen how a function can take arguments which implement a trait:
|
||||
|
||||
```rust,editable
|
||||
use std::fmt::Display;
|
||||
|
||||
fn print<T: Display>(x: T) {
|
||||
println!("Your value: {}", x);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
print(123);
|
||||
print("Hello");
|
||||
}
|
||||
```
|
||||
|
||||
However, how can we store a collection of mixed types which implement `Display`?
|
||||
|
||||
```rust,editable,compile_fail
|
||||
fn main() {
|
||||
let xs = vec![123, "Hello"];
|
||||
}
|
||||
```
|
||||
|
||||
For this, we need _trait objects_:
|
||||
|
||||
```rust,editable
|
||||
use std::fmt::Display;
|
||||
|
||||
fn main() {
|
||||
let xs: Vec<Box<dyn Display>> = vec![Box::new(123), Box::new("Hello")];
|
||||
for x in xs {
|
||||
println!("x: {x}");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Memory layout after allocating `xs`:
|
||||
|
||||
```bob
|
||||
Stack Heap
|
||||
.- - - - - - - - - - - - - -. .- - - - - - - - - - - - - - - - - - - - - - - -.
|
||||
: : : :
|
||||
: xs : : :
|
||||
: +-----------+-------+ : : +-----+-----+ :
|
||||
: | ptr | o---+---+-----+-->| o o | o o | :
|
||||
: | len | 2 | : : +-|-|-+-|-|-+ :
|
||||
: | capacity | 2 | : : | | | | +----+----+----+----+----+ :
|
||||
: +-----------+-------+ : : | | | '-->| H | e | l | l | o | :
|
||||
: : : | | | +----+----+----+----+----+ :
|
||||
`- - - - - - - - - - - - - -' : | | | :
|
||||
: | | | +-------------------------+ :
|
||||
: | | '---->| "<str as Display>::fmt" | :
|
||||
: | | +-------------------------+ :
|
||||
: | | :
|
||||
: | | +-------------------------+ :
|
||||
: | '-->| "<i32 as Display>::fmt" | :
|
||||
: | +-------------------------+ :
|
||||
: | :
|
||||
: | +----+----+----+----+ :
|
||||
: '---->| 7b | 00 | 00 | 00 | :
|
||||
: +----+----+----+----+ :
|
||||
: :
|
||||
: :
|
||||
'- - - - - - - - - - - - - - - - - - - - - - - -'
|
||||
```
|
||||
|
||||
Similarly, you need a trait object if you want to return different values
|
||||
implementing a trait:
|
||||
|
||||
```rust,editable
|
||||
fn numbers(n: i32) -> Box<dyn Iterator<Item=i32>> {
|
||||
if n > 0 {
|
||||
Box::new(0..n)
|
||||
} else {
|
||||
Box::new((n..0).rev())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("{:?}", numbers(-5).collect::<Vec<_>>());
|
||||
println!("{:?}", numbers(5).collect::<Vec<_>>());
|
||||
}
|
||||
|
||||
```
|
Reference in New Issue
Block a user