@@ -991,11 +991,281 @@ generally, you want to export documentation for a full module.
991
991
992
992
## Compound Data Types
993
993
994
- Tuples
994
+ Rust, like many programming languages, has a number of different data types
995
+ that are built-in. You've already done some simple work with integers and
996
+ strings, but next, let's talk about some more complicated ways of storing data.
995
997
996
- Structs
998
+ ### Tuples
997
999
998
- Enums
1000
+ The first compound data type we're going to talk about are called ** tuple** s.
1001
+ Tuples are an ordered list of a fixed size. Like this:
1002
+
1003
+ ``` rust
1004
+ let x = (1i , " hello" );
1005
+ ```
1006
+
1007
+ The parenthesis and commas form this two-length tuple. Here's the same code, but
1008
+ with the type annotated:
1009
+
1010
+ ``` rust
1011
+ let x : (int , & str ) = (1 , " hello" );
1012
+ ```
1013
+
1014
+ As you can see, the type of a tuple looks just like the tuple, but with each
1015
+ position having a type name rather than the value. Careful readers will also
1016
+ note that tuples are heterogeneous: we have an ` int ` and a ` &str ` in this tuple.
1017
+ You haven't seen ` &str ` as a type before, and we'll discuss the details of
1018
+ strings later. In systems programming languages, strings are a bit more complex
1019
+ than in other languages. For now, just read ` &str ` as "a string slice," and
1020
+ we'll learn more soon.
1021
+
1022
+ You can access the fields in a tuple through a ** destructuring let** . Here's
1023
+ an example:
1024
+
1025
+ ``` rust
1026
+ let (x , y , z ) = (1i , 2i , 3i );
1027
+
1028
+ println! (" x is {}" , x );
1029
+ ```
1030
+
1031
+ Remember before when I said the left hand side of a ` let ` statement was more
1032
+ powerful than just assigning a binding? Here we are. We can put a pattern on
1033
+ the left hand side of the ` let ` , and if it matches up to the right hand side,
1034
+ we can assign multiple bindings at once. In this case, ` let ` 'destructures,'
1035
+ or 'breaks up,' the tuple, and assigns the bits to three bindings.
1036
+
1037
+ This pattern is very powerful, and we'll see it repeated more later.
1038
+
1039
+ The last thing to say about tuples is that they are only equivalent if
1040
+ the arity, types, and values are all identical.
1041
+
1042
+ ``` rust
1043
+ let x = (1i , 2i , 3i );
1044
+ let y = (2i , 3i , 4i );
1045
+
1046
+ if x == y {
1047
+ println! (" yes" );
1048
+ } else {
1049
+ println! (" no" );
1050
+ }
1051
+ ```
1052
+
1053
+ This will print ` no ` , as the values aren't equal.
1054
+
1055
+ One other use of tuples is to return multiple values from a function:
1056
+
1057
+ ``` rust
1058
+ fn next_two (x : int ) -> (int , int ) { (x + 1i , x + 2i ) }
1059
+
1060
+ fn main () {
1061
+ let (x , y ) = next_two (5i );
1062
+ println! (" x, y = {}, {}" , x , y );
1063
+ }
1064
+ ```
1065
+
1066
+ Even though Rust functions can only return one value, a tuple _ is_ one value,
1067
+ that happens to be made up of two. You can also see in this example how you
1068
+ can destructure a pattern returned by a function, as well.
1069
+
1070
+ Tuples are a very simple data structure, and so are not often what you want.
1071
+ Let's move on to their bigger sibling, structs.
1072
+
1073
+ ### Structs
1074
+
1075
+ A struct is another form of a 'record type,' just like a tuple. There's a
1076
+ difference: structs give each element that they contain a name, called a
1077
+ 'field' or a 'member.' Check it out:
1078
+
1079
+ ``` rust
1080
+ struct Point {
1081
+ x : int ,
1082
+ y : int ,
1083
+ }
1084
+
1085
+ fn main () {
1086
+ let origin = Point { x : 0i , y : 0i };
1087
+
1088
+ println! (" The origin is at ({}, {})" , origin . x, origin . y);
1089
+ }
1090
+ ```
1091
+
1092
+ There's a lot going on here, so let's break it down. We declare a struct with
1093
+ the ` struct ` keyword, and then with a name. By convention, structs begin with a
1094
+ capital letter and are also camel cased: ` PointInSpace ` , not ` Point_In_Space ` .
1095
+
1096
+ We can create an instance of our struct via ` let ` , as usual, but we use a `key:
1097
+ value` style syntax to set each field. The order doesn't need to be the same as
1098
+ in the original declaration.
1099
+
1100
+ Finally, because fields have names, we can access the field through dot
1101
+ notation: ` origin.x ` .
1102
+
1103
+ The values in structs are immutable, like other bindings in Rust. However, you
1104
+ can use ` mut ` to make them mutable:
1105
+
1106
+ ``` rust
1107
+ struct Point {
1108
+ x : int ,
1109
+ y : int ,
1110
+ }
1111
+
1112
+ fn main () {
1113
+ let mut point = Point { x : 0i , y : 0i };
1114
+
1115
+ point . x = 5 ;
1116
+
1117
+ println! (" The point is at ({}, {})" , point . x, point . y);
1118
+ }
1119
+ ```
1120
+
1121
+ This will print ` The point is at (5, 0) ` .
1122
+
1123
+ ### Tuple Structs and Newtypes
1124
+
1125
+ Rust has another data type that's like a hybrid between a tuple and a struct,
1126
+ called a ** tuple struct** . Tuple structs do have a name, but their fields
1127
+ don't:
1128
+
1129
+
1130
+ ```
1131
+ struct Color(int, int, int);
1132
+ struct Point(int, int, int);
1133
+ ```
1134
+
1135
+ These two will not be equal, even if they have the same values:
1136
+
1137
+ ``` {rust,ignore}
1138
+ let black = Color(0, 0, 0);
1139
+ let origin = Point(0, 0, 0);
1140
+ ```
1141
+
1142
+ It is almost always better to use a struct than a tuple struct. We would write
1143
+ ` Color ` and ` Point ` like this instead:
1144
+
1145
+ ``` rust
1146
+ struct Color {
1147
+ red : int ,
1148
+ blue : int ,
1149
+ green : int ,
1150
+ }
1151
+
1152
+ struct Point {
1153
+ x : int ,
1154
+ y : int ,
1155
+ z : int ,
1156
+ }
1157
+ ```
1158
+
1159
+ Now, we have actual names, rather than positions. Good names are important,
1160
+ and with a struct, we have actual names.
1161
+
1162
+ There _ is_ one case when a tuple struct is very useful, though, and that's a
1163
+ tuple struct with only one element. We call this a 'newtype,' because it lets
1164
+ you create a new type that's a synonym for another one:
1165
+
1166
+ ```
1167
+ struct Inches(int);
1168
+ struct Centimeters(int);
1169
+
1170
+ let length = Inches(10);
1171
+
1172
+ let Inches(integer_length) = length;
1173
+ println!("length is {} inches", integer_length);
1174
+ ```
1175
+
1176
+ As you can see here, you can extract the inner integer type through a
1177
+ destructuring ` let ` .
1178
+
1179
+ ### Enums
1180
+
1181
+ Finally, Rust has a "sum type", an ** enum** . Enums are an incredibly useful
1182
+ feature of Rust, and are used throughout the standard library. Enums look
1183
+ like this:
1184
+
1185
+ ```
1186
+ enum Ordering {
1187
+ Less,
1188
+ Equal,
1189
+ Greater,
1190
+ }
1191
+ ```
1192
+
1193
+ This is an enum that is provided by the Rust standard library. An ` Ordering `
1194
+ can only be _ one_ of ` Less ` , ` Equal ` , or ` Greater ` at any given time. Here's
1195
+ an example:
1196
+
1197
+ ``` rust
1198
+ let x = 5i ;
1199
+ let y = 10i ;
1200
+
1201
+ let ordering = x . cmp (& y );
1202
+
1203
+ if ordering == Less {
1204
+ println! (" less" );
1205
+ } else if ordering == Greater {
1206
+ println! (" greater" );
1207
+ } else if ordering == Equal {
1208
+ println! (" equal" );
1209
+ }
1210
+ ```
1211
+
1212
+ ` cmp ` is a function that compares two things, and returns an ` Ordering ` . The
1213
+ call looks a little bit strange: rather than ` cmp(x, y) ` , we say ` x.cmp(&y) ` .
1214
+ We haven't covered methods and references yet, so it should look a little bit
1215
+ foreign. Right now, just pretend it says ` cmp(x, y) ` , and we'll get to those
1216
+ details soon.
1217
+
1218
+ The ` ordering ` variable has the type ` Ordering ` , and so contains one of the
1219
+ three values. We can then do a bunch of ` if ` /` else ` comparisons to check
1220
+ which one it is.
1221
+
1222
+ However, repeated ` if ` /` else ` comparisons get quite tedious. Rust has a feature
1223
+ that not only makes them nicer to read, but also makes sure that you never
1224
+ miss a case. Before we get to that, though, let's talk about another kind of
1225
+ enum: one with values.
1226
+
1227
+ This enum has two variants, one of which has a value.:
1228
+
1229
+ ```
1230
+ enum OptionalInt {
1231
+ Value(int),
1232
+ Missing
1233
+ }
1234
+
1235
+ fn main() {
1236
+ let x = Value(5);
1237
+ let y = Missing;
1238
+
1239
+ match x {
1240
+ Value(n) => println!("x is {:d}", n),
1241
+ Missing => println!("x is missing!"),
1242
+ }
1243
+
1244
+ match y {
1245
+ Value(n) => println!("y is {:d}", n),
1246
+ Missing => println!("y is missing!"),
1247
+ }
1248
+ }
1249
+ ```
1250
+
1251
+ This enum represents an ` int ` that we may or may not have. In the ` Missing `
1252
+ case, we have no value, but in the ` Value ` case, we do. This enum is specific
1253
+ to ` int ` s, though. We can make it usable by any type, but we haven't quite
1254
+ gotten there yet!
1255
+
1256
+ You can have any number of values in an enum:
1257
+
1258
+ ```
1259
+ enum OptionalColor {
1260
+ Color(int, int, int),
1261
+ Missing
1262
+ }
1263
+ ```
1264
+
1265
+ Enums with values are quite useful, but as I mentioned, they're even more
1266
+ useful when they're generic across types. But before we get to generics, let's
1267
+ talk about how to fix this big ` if ` /` else ` statements we've been writing. We'll
1268
+ do that with ` match ` .
999
1269
1000
1270
## Match
1001
1271
0 commit comments