Auto merge of #23822 - tanadeau:remove-box-syntax-in-pointers-doc, r=steveklabnik
This is the first use of `box`. It's an unstable feature and also isn't consistent with the use of `Box` in the "original" code above it. r? @steveklabnik
This commit is contained in:
commit
3e8a773bc5
@ -43,5 +43,6 @@
|
||||
* [Lang items](lang-items.md)
|
||||
* [Link args](link-args.md)
|
||||
* [Benchmark Tests](benchmark-tests.md)
|
||||
* [Box Syntax and Patterns](box-syntax-and-patterns.md)
|
||||
* [Conclusion](conclusion.md)
|
||||
* [Glossary](glossary.md)
|
||||
|
100
src/doc/trpl/box-syntax-and-patterns.md
Normal file
100
src/doc/trpl/box-syntax-and-patterns.md
Normal file
@ -0,0 +1,100 @@
|
||||
% Box Syntax and Patterns
|
||||
|
||||
Currently the only stable way to create a `Box` is via the `Box::new` method.
|
||||
Also it is not possible in stable Rust to destructure a `Box` in a match
|
||||
pattern. The unstable `box` keyword can be used to both create and destructure
|
||||
a `Box`. An example usage would be:
|
||||
|
||||
```
|
||||
#![feature(box_syntax, box_patterns)]
|
||||
|
||||
fn main() {
|
||||
let b = Some(box 5);
|
||||
match b {
|
||||
Some(box n) if n < 0 => {
|
||||
println!("Box contains negative number {}", n);
|
||||
},
|
||||
Some(box n) if n >= 0 => {
|
||||
println!("Box contains non-negative number {}", n);
|
||||
},
|
||||
None => {
|
||||
println!("No box");
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note that these features are currently hidden behind the `box_syntax` (box
|
||||
creation) and `box_patterns` (destructuring and pattern matching) gates
|
||||
because the syntax may still change in the future.
|
||||
|
||||
# Returning Pointers
|
||||
|
||||
In many languages with pointers, you'd return a pointer from a function
|
||||
so as to avoid copying a large data structure. For example:
|
||||
|
||||
```{rust}
|
||||
struct BigStruct {
|
||||
one: i32,
|
||||
two: i32,
|
||||
// etc
|
||||
one_hundred: i32,
|
||||
}
|
||||
|
||||
fn foo(x: Box<BigStruct>) -> Box<BigStruct> {
|
||||
Box::new(*x)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Box::new(BigStruct {
|
||||
one: 1,
|
||||
two: 2,
|
||||
one_hundred: 100,
|
||||
});
|
||||
|
||||
let y = foo(x);
|
||||
}
|
||||
```
|
||||
|
||||
The idea is that by passing around a box, you're only copying a pointer, rather
|
||||
than the hundred `int`s that make up the `BigStruct`.
|
||||
|
||||
This is an antipattern in Rust. Instead, write this:
|
||||
|
||||
```rust
|
||||
#![feature(box_syntax)]
|
||||
|
||||
struct BigStruct {
|
||||
one: i32,
|
||||
two: i32,
|
||||
// etc
|
||||
one_hundred: i32,
|
||||
}
|
||||
|
||||
fn foo(x: Box<BigStruct>) -> BigStruct {
|
||||
*x
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Box::new(BigStruct {
|
||||
one: 1,
|
||||
two: 2,
|
||||
one_hundred: 100,
|
||||
});
|
||||
|
||||
let y: Box<BigStruct> = box foo(x);
|
||||
}
|
||||
```
|
||||
|
||||
This gives you flexibility without sacrificing performance.
|
||||
|
||||
You may think that this gives us terrible performance: return a value and then
|
||||
immediately box it up ?! Isn't this pattern the worst of both worlds? Rust is
|
||||
smarter than that. There is no copy in this code. `main` allocates enough room
|
||||
for the `box`, passes a pointer to that memory into `foo` as `x`, and then
|
||||
`foo` writes the value straight into the `Box<T>`.
|
||||
|
||||
This is important enough that it bears repeating: pointers are not for
|
||||
optimizing returning values from your code. Allow the caller to choose how they
|
||||
want to use your output.
|
@ -574,7 +574,7 @@ fn main() {
|
||||
```
|
||||
|
||||
We can mutably borrow `x` multiple times, but only if x itself is mutable, and
|
||||
it may not be *simultaneously* borrowed:
|
||||
it may not be *simultaneously* borrowed:
|
||||
|
||||
```{rust,ignore}
|
||||
fn increment(x: &mut i32) {
|
||||
@ -595,8 +595,7 @@ Notice the signature of `increment()` requests a mutable reference.
|
||||
|
||||
## Best practices
|
||||
|
||||
Boxes are appropriate to use in two situations: Recursive data structures,
|
||||
and occasionally, when returning data.
|
||||
Boxes are most appropriate to use when defining recursive data structures.
|
||||
|
||||
### Recursive data structures
|
||||
|
||||
@ -630,14 +629,6 @@ we don't know the size, and therefore, we need to heap allocate our list.
|
||||
Working with recursive or other unknown-sized data structures is the primary
|
||||
use-case for boxes.
|
||||
|
||||
### Returning data
|
||||
|
||||
This is important enough to have its own section entirely. The TL;DR is this:
|
||||
you don't want to return pointers, even when you might in a language like C or
|
||||
C++.
|
||||
|
||||
See [Returning Pointers](#returning-pointers) below for more.
|
||||
|
||||
# Rc and Arc
|
||||
|
||||
This part is coming soon.
|
||||
@ -654,79 +645,6 @@ This part is coming soon.
|
||||
|
||||
This part is coming soon.
|
||||
|
||||
# Returning Pointers
|
||||
|
||||
In many languages with pointers, you'd return a pointer from a function
|
||||
so as to avoid copying a large data structure. For example:
|
||||
|
||||
```{rust}
|
||||
struct BigStruct {
|
||||
one: i32,
|
||||
two: i32,
|
||||
// etc
|
||||
one_hundred: i32,
|
||||
}
|
||||
|
||||
fn foo(x: Box<BigStruct>) -> Box<BigStruct> {
|
||||
Box::new(*x)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Box::new(BigStruct {
|
||||
one: 1,
|
||||
two: 2,
|
||||
one_hundred: 100,
|
||||
});
|
||||
|
||||
let y = foo(x);
|
||||
}
|
||||
```
|
||||
|
||||
The idea is that by passing around a box, you're only copying a pointer, rather
|
||||
than the hundred `int`s that make up the `BigStruct`.
|
||||
|
||||
This is an antipattern in Rust. Instead, write this:
|
||||
|
||||
```rust
|
||||
#![feature(box_syntax)]
|
||||
|
||||
struct BigStruct {
|
||||
one: i32,
|
||||
two: i32,
|
||||
// etc
|
||||
one_hundred: i32,
|
||||
}
|
||||
|
||||
fn foo(x: Box<BigStruct>) -> BigStruct {
|
||||
*x
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Box::new(BigStruct {
|
||||
one: 1,
|
||||
two: 2,
|
||||
one_hundred: 100,
|
||||
});
|
||||
|
||||
let y: Box<BigStruct> = box foo(x);
|
||||
}
|
||||
```
|
||||
|
||||
Note that this uses the `box_syntax` feature gate, so this syntax may change in
|
||||
the future.
|
||||
|
||||
This gives you flexibility without sacrificing performance.
|
||||
|
||||
You may think that this gives us terrible performance: return a value and then
|
||||
immediately box it up ?! Isn't this pattern the worst of both worlds? Rust is
|
||||
smarter than that. There is no copy in this code. `main` allocates enough room
|
||||
for the `box`, passes a pointer to that memory into `foo` as `x`, and then
|
||||
`foo` writes the value straight into the `Box<T>`.
|
||||
|
||||
This is important enough that it bears repeating: pointers are not for
|
||||
optimizing returning values from your code. Allow the caller to choose how they
|
||||
want to use your output.
|
||||
|
||||
# Creating your own Pointers
|
||||
|
||||
This part is coming soon.
|
||||
|
Loading…
x
Reference in New Issue
Block a user