diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index 136e155b1af..11e62aff42f 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -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) diff --git a/src/doc/trpl/box-syntax-and-patterns.md b/src/doc/trpl/box-syntax-and-patterns.md new file mode 100644 index 00000000000..839f07d9843 --- /dev/null +++ b/src/doc/trpl/box-syntax-and-patterns.md @@ -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) -> Box { + 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 { + *x +} + +fn main() { + let x = Box::new(BigStruct { + one: 1, + two: 2, + one_hundred: 100, + }); + + let y: Box = 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`. + +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. diff --git a/src/doc/trpl/pointers.md b/src/doc/trpl/pointers.md index 107d7d979a0..1b3f2a5b773 100644 --- a/src/doc/trpl/pointers.md +++ b/src/doc/trpl/pointers.md @@ -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) -> Box { - 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 { - *x -} - -fn main() { - let x = Box::new(BigStruct { - one: 1, - two: 2, - one_hundred: 100, - }); - - let y: Box = 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`. - -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.