@@ -923,22 +923,60 @@ custom destructors.
923
923
924
924
# Boxes
925
925
926
- Many modern languages represent values as pointers to heap memory by
927
- default. In contrast, Rust, like C and C++, represents such types directly.
928
- Another way to say this is that aggregate data in Rust are * unboxed* . This
929
- means that if you ` let x = Point { x: 1f, y: 1f }; ` , you are creating a struct
930
- on the stack. If you then copy it into a data structure, you copy the entire
931
- struct, not just a pointer.
926
+ A value in Rust is stored directly inside the owner. If a ` struct ` contains
927
+ four ` int ` fields, it will be four times as large as a single ` int ` . The
928
+ following ` struct ` type is invalid, as it would have an infinite size:
932
929
933
- For small structs like ` Point ` , this is usually more efficient than allocating
934
- memory and indirecting through a pointer. But for big structs, or mutable
935
- state, it can be useful to have a single copy on the stack or on the heap, and
936
- refer to that through a pointer.
930
+ ~~~~ {.xfail-test}
931
+ struct List {
932
+ next: Option<List>,
933
+ data: int
934
+ }
935
+ ~~~~
936
+
937
+ > *** Note:*** The ` Option ` type is an enum representing an * optional* value.
938
+ > It's comparable to a nullable pointer in many other languages, but stores the
939
+ > contained value unboxed.
940
+
941
+ An * owned box* (` ~ ` ) uses a heap allocation to provide the invariant of always
942
+ being the size of a pointer, regardless of the contained type. This can be
943
+ leveraged to create a valid recursive ` struct ` type with a finite size:
944
+
945
+ ~~~~
946
+ struct List {
947
+ next: Option<~List>,
948
+ data: int
949
+ }
950
+ ~~~~
951
+
952
+ Since an owned box has a single owner, they are limited to representing
953
+ tree-like data structures.
954
+
955
+ The most common use case for owned boxes is creating recursive data structures
956
+ like a binary search tree. Rust's trait-based generics system (covered later in
957
+ the tutorial) is usually used for static dispatch, but also provides dynamic
958
+ dispatch via boxing. Values of different types may have different sizes, but a
959
+ box is able to * erase* the difference via the layer of indirection they
960
+ provide.
937
961
938
- ## Owned boxes
962
+ In uncommon cases, the indirection can provide a performance gain or memory
963
+ reduction by making values smaller. However, unboxed values should almost
964
+ always be preferred.
939
965
940
- An owned box (` ~ ` ) is a uniquely owned allocation on the heap. It inherits the
941
- mutability and lifetime of the owner as it would if there was no box:
966
+ Note that returning large unboxed values via boxes is unnecessary. A large
967
+ value is returned via a hidden output parameter, and the decision on where to
968
+ place the return value should be left to the caller:
969
+
970
+ ~~~~
971
+ fn foo() -> (int, int, int, int, int, int) {
972
+ (5, 5, 5, 5, 5, 5)
973
+ }
974
+
975
+ let x = ~foo(); // allocates, and writes the integers directly to it
976
+ ~~~~
977
+
978
+ Beyond the properties granted by the size, an owned box behaves as a regular
979
+ value by inheriting the mutability and lifetime of the owner:
942
980
943
981
~~~~
944
982
let x = 5; // immutable
@@ -950,35 +988,33 @@ let mut y = ~5; // mutable
950
988
*y += 2; // the * operator is needed to access the contained value
951
989
~~~~
952
990
953
- The purpose of an owned box is to add a layer of indirection in order to create
954
- recursive data structures or cheaply pass around an object larger than a
955
- pointer. Since an owned box has a unique owner, it can only be used to
956
- represent a tree data structure.
991
+ As covered earlier, an owned box has a destructor to clean up the allocated
992
+ memory. This makes it more restricted than an unboxed type with no destructor
993
+ by introducing * move semantics* .
957
994
958
- The following struct won't compile, because the lack of indirection would mean
959
- it has an infinite size:
995
+ # Move semantics
960
996
961
- ~~~~ {.xfail-test}
962
- struct Foo {
963
- child: Option<Foo>
964
- }
965
- ~~~~
997
+ Rust uses a shallow copy for parameter passing, assignment and returning from
998
+ functions. This is considered a move of ownership for types with destructors.
999
+ After a value has been moved, it can no longer be used from the source location
1000
+ and will not be destroyed when the source goes out of scope.
966
1001
967
- > *** Note:*** The ` Option ` type is an enum that represents an * optional* value.
968
- > It's comparable to a nullable pointer in many other languages, but stores the
969
- > contained value unboxed.
1002
+ ~~~~
1003
+ let x = ~5;
1004
+ let y = x.clone(); // y is a newly allocated box
1005
+ let z = x; // no new memory allocated, x can no longer be used
1006
+ ~~~~
970
1007
971
- Adding indirection with an owned pointer allocates the child outside of the
972
- struct on the heap, which makes it a finite size and won't result in a
973
- compile-time error:
1008
+ The mutability of a value may be changed by moving it to a new owner:
974
1009
975
1010
~~~~
976
- struct Foo {
977
- child: Option<~Foo>
978
- }
1011
+ let r = ~13;
1012
+ let mut s = r; // box becomes mutable
1013
+ *s += 1;
1014
+ let t = s; // box becomes immutable
979
1015
~~~~
980
1016
981
- ## Managed boxes
1017
+ # Managed boxes
982
1018
983
1019
A managed box (` @ ` ) is a heap allocation with the lifetime managed by a
984
1020
task-local garbage collector. It will be destroyed at some point after there
@@ -1023,30 +1059,6 @@ d = b; // box type is the same, okay
1023
1059
c = b; // error
1024
1060
~~~~
1025
1061
1026
- # Move semantics
1027
-
1028
- Rust uses a shallow copy for parameter passing, assignment and returning values
1029
- from functions. A shallow copy is considered a move of ownership if the
1030
- ownership tree of the copied value includes an owned box or a type with a
1031
- custom destructor. After a value has been moved, it can no longer be used from
1032
- the source location and will not be destroyed there.
1033
-
1034
- ~~~~
1035
- let x = ~5;
1036
- let y = x.clone(); // y is a newly allocated box
1037
- let z = x; // no new memory allocated, x can no longer be used
1038
- ~~~~
1039
-
1040
- Since in owned boxes mutability is a property of the owner, not the
1041
- box, mutable boxes may become immutable when they are moved, and vice-versa.
1042
-
1043
- ~~~~
1044
- let r = ~13;
1045
- let mut s = r; // box becomes mutable
1046
- *s += 1;
1047
- let t = s; // box becomes immutable
1048
- ~~~~
1049
-
1050
1062
# Borrowed pointers
1051
1063
1052
1064
Rust's borrowed pointers are a general purpose reference type. In contrast with
0 commit comments