Skip to content

Commit 14af257

Browse files
committed
TRPL edits: generics
1 parent 1c48227 commit 14af257

File tree

1 file changed

+72
-40
lines changed

1 file changed

+72
-40
lines changed

src/doc/trpl/generics.md

+72-40
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,13 @@
11
% Generics
22

33
Sometimes, when writing a function or data type, we may want it to work for
4-
multiple types of arguments. For example, remember our `OptionalInt` type?
4+
multiple types of arguments. Luckily, Rust has a feature that gives us a better
5+
way: generics. Generics are called ‘parametric polymorphism’ in type theory,
6+
which means that they are types or functions that have multiple forms (‘poly’
7+
is multiple, ‘morph’ is form) over a given parameter (‘parametric’).
58

6-
```{rust}
7-
enum OptionalInt {
8-
Value(i32),
9-
Missing,
10-
}
11-
```
12-
13-
If we wanted to also have an `OptionalFloat64`, we would need a new enum:
14-
15-
```{rust}
16-
enum OptionalFloat64 {
17-
Valuef64(f64),
18-
Missingf64,
19-
}
20-
```
21-
22-
This is really unfortunate. Luckily, Rust has a feature that gives us a better
23-
way: generics. Generics are called *parametric polymorphism* in type theory,
24-
which means that they are types or functions that have multiple forms (*poly*
25-
is multiple, *morph* is form) over a given parameter (*parametric*).
26-
27-
Anyway, enough with type theory declarations, let's check out the generic form
28-
of `OptionalInt`. It is actually provided by Rust itself, and looks like this:
9+
Anyway, enough with type theory, let’s check out some generic code. Rust’s
10+
standard library provides a type, `Option<T>`, that’s generic:
2911

3012
```rust
3113
enum Option<T> {
@@ -34,59 +16,109 @@ enum Option<T> {
3416
}
3517
```
3618

37-
The `<T>` part, which you've seen a few times before, indicates that this is
19+
The `<T>` part, which youve seen a few times before, indicates that this is
3820
a generic data type. Inside the declaration of our enum, wherever we see a `T`,
39-
we substitute that type for the same type used in the generic. Here's an
21+
we substitute that type for the same type used in the generic. Heres an
4022
example of using `Option<T>`, with some extra type annotations:
4123

42-
```{rust}
24+
```rust
4325
let x: Option<i32> = Some(5);
4426
```
4527

4628
In the type declaration, we say `Option<i32>`. Note how similar this looks to
4729
`Option<T>`. So, in this particular `Option`, `T` has the value of `i32`. On
4830
the right-hand side of the binding, we do make a `Some(T)`, where `T` is `5`.
49-
Since that's an `i32`, the two sides match, and Rust is happy. If they didn't
50-
match, we'd get an error:
31+
Since thats an `i32`, the two sides match, and Rust is happy. If they didnt
32+
match, wed get an error:
5133

52-
```{rust,ignore}
34+
```rust,ignore
5335
let x: Option<f64> = Some(5);
5436
// error: mismatched types: expected `core::option::Option<f64>`,
5537
// found `core::option::Option<_>` (expected f64 but found integral variable)
5638
```
5739

58-
That doesn't mean we can't make `Option<T>`s that hold an `f64`! They just have to
59-
match up:
40+
That doesnt mean we cant make `Option<T>`s that hold an `f64`! They just have
41+
to match up:
6042

61-
```{rust}
43+
```rust
6244
let x: Option<i32> = Some(5);
6345
let y: Option<f64> = Some(5.0f64);
6446
```
6547

6648
This is just fine. One definition, multiple uses.
6749

68-
Generics don't have to only be generic over one type. Consider Rust's built-in
69-
`Result<T, E>` type:
50+
Generics don’t have to only be generic over one type. Consider another type from Rust’s standard library that’s similar, `Result<T, E>`:
7051

71-
```{rust}
52+
```rust
7253
enum Result<T, E> {
7354
Ok(T),
7455
Err(E),
7556
}
7657
```
7758

7859
This type is generic over _two_ types: `T` and `E`. By the way, the capital letters
79-
can be any letter you'd like. We could define `Result<T, E>` as:
60+
can be any letter youd like. We could define `Result<T, E>` as:
8061

81-
```{rust}
62+
```rust
8263
enum Result<A, Z> {
8364
Ok(A),
8465
Err(Z),
8566
}
8667
```
8768

8869
if we wanted to. Convention says that the first generic parameter should be
89-
`T`, for 'type,' and that we use `E` for 'error.' Rust doesn't care, however.
70+
`T`, for type’, and that we use `E` for error’. Rust doesnt care, however.
9071

9172
The `Result<T, E>` type is intended to be used to return the result of a
92-
computation, and to have the ability to return an error if it didn't work out.
73+
computation, and to have the ability to return an error if it didn’t work out.
74+
75+
## Generic functions
76+
77+
We can write functions that take generic types with a similar syntax:
78+
79+
```rust
80+
fn takes_anything<T>(x: T) {
81+
// do something with x
82+
}
83+
```
84+
85+
The syntax has two parts: the `<T>` says “this function is generic over one
86+
type, `T`”, and the `x: T` says “x has the type `T`.”
87+
88+
Multiple arguments can have the same generic type:
89+
90+
```rust
91+
fn takes_two_of_the_same_things<T>(x: T, y: T) {
92+
// ...
93+
}
94+
```
95+
96+
We could write a version that takes multiple types:
97+
98+
```rust
99+
fn takes_two_things<T, U>(x: T, y: U) {
100+
// ...
101+
}
102+
```
103+
104+
Generic functions are most useful with ‘trait bounds’, which we’ll cover in the
105+
[section on traits][traits].
106+
107+
[traits]: traits.html
108+
109+
## Generic structs
110+
111+
You can store a generic type in a `struct` as well:
112+
113+
```
114+
struct Point<T> {
115+
x: T,
116+
y: T,
117+
}
118+
119+
let int_origin = Point { x: 0, y: 0 };
120+
let float_origin = Point { x: 0.0, y: 0.0 };
121+
```
122+
123+
Similarly to functions, the `<T>` is where we declare the generic parameters,
124+
and we then use `x: T` in the type declaration, too.

0 commit comments

Comments
 (0)