@@ -923,60 +923,22 @@ custom destructors.
923
923
924
924
# Boxes
925
925
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:
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.
929
932
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.
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.
961
937
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.
938
+ ## Owned boxes
965
939
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:
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:
980
942
981
943
~~~~
982
944
let x = 5; // immutable
@@ -988,33 +950,35 @@ let mut y = ~5; // mutable
988
950
*y += 2; // the * operator is needed to access the contained value
989
951
~~~~
990
952
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* .
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.
994
957
995
- # Move semantics
958
+ The following struct won't compile, because the lack of indirection would mean
959
+ it has an infinite size:
996
960
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.
1001
-
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
961
+ ~~~~ {.xfail-test}
962
+ struct Foo {
963
+ child: Option<Foo>
964
+ }
1006
965
~~~~
1007
966
1008
- The mutability of a value may be changed by moving it to a new owner:
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.
970
+
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:
1009
974
1010
975
~~~~
1011
- let r = ~13;
1012
- let mut s = r; // box becomes mutable
1013
- *s += 1;
1014
- let t = s; // box becomes immutable
976
+ struct Foo {
977
+ child: Option<~Foo>
978
+ }
1015
979
~~~~
1016
980
1017
- # Managed boxes
981
+ ## Managed boxes
1018
982
1019
983
A managed box (` @ ` ) is a heap allocation with the lifetime managed by a
1020
984
task-local garbage collector. It will be destroyed at some point after there
@@ -1059,6 +1023,30 @@ d = b; // box type is the same, okay
1059
1023
c = b; // error
1060
1024
~~~~
1061
1025
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
+
1062
1050
# Borrowed pointers
1063
1051
1064
1052
Rust's borrowed pointers are a general purpose reference type. In contrast with
0 commit comments