]> git.proxmox.com Git - rustc.git/blobdiff - src/doc/book/src/ch10-01-syntax.md
New upstream version 1.61.0+dfsg1
[rustc.git] / src / doc / book / src / ch10-01-syntax.md
index e3b3a6c5b6bf7848c77bb5c4f12bdc65c749e4a3..c2ed68d0961676d160a2d505059569191152728e 100644 (file)
@@ -1,6 +1,6 @@
 ## Generic Data Types
 
-We can use generics to create definitions for items like function signatures or
+We use generics to create definitions for items like function signatures or
 structs, which we can then use with many different concrete data types. Let’s
 first look at how to define functions, structs, enums, and methods using
 generics. Then we’ll discuss how generics affect code performance.
@@ -13,7 +13,8 @@ parameters and return value. Doing so makes our code more flexible and provides
 more functionality to callers of our function while preventing code duplication.
 
 Continuing with our `largest` function, Listing 10-4 shows two functions that
-both find the largest value in a slice.
+both find the largest value in a slice. We'll then combine these into a single
+function that uses generics.
 
 <span class="filename">Filename: src/main.rs</span>
 
@@ -29,9 +30,9 @@ the largest `i32` in a slice. The `largest_char` function finds the largest
 `char` in a slice. The function bodies have the same code, so let’s eliminate
 the duplication by introducing a generic type parameter in a single function.
 
-To parameterize the types in the new function we’ll define, we need to name the
-type parameter, just as we do for the value parameters to a function. You can
-use any identifier as a type parameter name. But we’ll use `T` because, by
+To parameterize the types in a new single function, we need to name the type
+parameter, just as we do for the value parameters to a function. You can use
+any identifier as a type parameter name. But we’ll use `T` because, by
 convention, parameter names in Rust are short, often just a letter, and Rust’s
 type-naming convention is CamelCase. Short for “type,” `T` is the default
 choice of most Rust programmers.
@@ -63,8 +64,8 @@ compile yet, but we’ll fix it later in this chapter.
 {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/src/main.rs}}
 ```
 
-<span class="caption">Listing 10-5: A definition of the `largest` function that
-uses generic type parameters but doesn’t compile yet</span>
+<span class="caption">Listing 10-5: The `largest` function using generic type
+parameters; this doesn’t yet compile</span>
 
 If we compile this code right now, we’ll get this error:
 
@@ -73,21 +74,22 @@ If we compile this code right now, we’ll get this error:
 ```
 
 The note mentions `std::cmp::PartialOrd`, which is a *trait*. We’ll talk about
-traits in the next section. For now, this error states that the body of
-`largest` won’t work for all possible types that `T` could be. Because we want
-to compare values of type `T` in the body, we can only use types whose values
-can be ordered. To enable comparisons, the standard library has the
+traits in the next section. For now, know that this error states that the body
+of `largest` won’t work for all possible types that `T` could be. Because we
+want to compare values of type `T` in the body, we can only use types whose
+values can be ordered. To enable comparisons, the standard library has the
 `std::cmp::PartialOrd` trait that you can implement on types (see Appendix C
 for more on this trait). You’ll learn how to specify that a generic type has a
 particular trait in the [“Traits as Parameters”][traits-as-parameters]<!--
-ignore --> section, but let’s first explore other ways of using generic type
-parameters.
+ignore --> section. Before we fix this code (in the section [“Fixing the
+`largest` Function with Trait Bounds”][fixing]<!-- ignore -->), let’s first
+explore other ways of using generic type parameters.
 
 ### In Struct Definitions
 
 We can also define structs to use a generic type parameter in one or more
-fields using the `<>` syntax. Listing 10-6 shows how to define a `Point<T>`
-struct to hold `x` and `y` coordinate values of any type.
+fields using the `<>` syntax. Listing 10-6 defines a `Point<T>` struct to hold
+`x` and `y` coordinate values of any type.
 
 <span class="filename">Filename: src/main.rs</span>
 
@@ -100,9 +102,8 @@ values of type `T`</span>
 
 The syntax for using generics in struct definitions is similar to that used in
 function definitions. First, we declare the name of the type parameter inside
-angle brackets just after the name of the struct. Then we can use the generic
-type in the struct definition where we would otherwise specify concrete data
-types.
+angle brackets just after the name of the struct. Then we use the generic type
+in the struct definition where we would otherwise specify concrete data types.
 
 Note that because we’ve used only one generic type to define `Point<T>`, this
 definition says that the `Point<T>` struct is generic over some type `T`, and
@@ -119,8 +120,11 @@ Listing 10-7, our code won’t compile.
 <span class="caption">Listing 10-7: The fields `x` and `y` must be the same
 type because both have the same generic data type `T`.</span>
 
-In this example, when we assign the integer value 5 to `x`, we let the
-compiler know that the generic type `T` will be an integer for this instance of
+Listing 10-7: The fields `x` and `y` must be the same type because both have
+the same generic data type `T`.
+
+In this example, when we assign the integer value 5 to `x`, we let the compiler
+know that the generic type `T` will be an integer for this instance of
 `Point<T>`. Then when we specify 4.0 for `y`, which we’ve defined to have the
 same type as `x`, we’ll get a type mismatch error like this:
 
@@ -130,8 +134,8 @@ same type as `x`, we’ll get a type mismatch error like this:
 
 To define a `Point` struct where `x` and `y` are both generics but could have
 different types, we can use multiple generic type parameters. For example, in
-Listing 10-8, we can change the definition of `Point` to be generic over types
-`T` and `U` where `x` is of type `T` and `y` is of type `U`.
+Listing 10-8, we change the definition of `Point` to be generic over types `T`
+and `U` where `x` is of type `T` and `y` is of type `U`.
 
 <span class="filename">Filename: src/main.rs</span>
 
@@ -144,8 +148,9 @@ that `x` and `y` can be values of different types</span>
 
 Now all the instances of `Point` shown are allowed! You can use as many generic
 type parameters in a definition as you want, but using more than a few makes
-your code hard to read. When you need lots of generic types in your code, it
-could indicate that your code needs restructuring into smaller pieces.
+your code hard to read. If you're finding you need lots of generic types in
+your code, it could indicate that your code needs restructuring into smaller
+pieces.
 
 ### In Enum Definitions
 
@@ -160,10 +165,10 @@ enum Option<T> {
 }
 ```
 
-This definition should now make more sense to you. As you can see, `Option<T>`
-is an enum that is generic over type `T` and has two variants: `Some`, which
+This definition should now make more sense to you. As you can see, the
+`Option<T>` enum is generic over type `T` and has two variants: `Some`, which
 holds one value of type `T`, and a `None` variant that doesn’t hold any value.
-By using the `Option<T>` enum, we can express the abstract concept of having an
+By using the `Option<T>` enum, we can express the abstract concept of an
 optional value, and because `Option<T>` is generic, we can use this abstraction
 no matter what the type of the optional value is.
 
@@ -209,21 +214,20 @@ struct we defined in Listing 10-6 with a method named `x` implemented on it.
 Here, we’ve defined a method named `x` on `Point<T>` that returns a reference
 to the data in the field `x`.
 
-Note that we have to declare `T` just after `impl` so we can use it to specify
+Note that we have to declare `T` just after `impl` so we can use `T` to specify
 that we’re implementing methods on the type `Point<T>`. By declaring `T` as a
 generic type after `impl`, Rust can identify that the type in the angle
-brackets in `Point` is a generic type rather than a concrete type. Because this
-is declaring the generic again, we could have chosen a different name for the
-generic parameter than the generic parameter declared in the struct definition,
-but using the same name is conventional. Methods written within an `impl` that
-declares the generic type will be defined on any instance of the type, no
-matter what concrete type ends up substituting for the generic type.
-
-The other option we have is defining methods on the type with some constraint
-on the generic type. We could, for example, implement methods only on
-`Point<f32>` instances rather than on `Point<T>` instances with any generic
-type. In Listing 10-10 we use the concrete type `f32`, meaning we don’t declare
-any types after `impl`.
+brackets in `Point` is a generic type rather than a concrete type. We could
+have chosen a different name for this generic parameter than the generic
+parameter declared in the struct definition, but using the same name is
+conventional. Methods written within an `impl` that declares the generic type
+will be defined on any instance of the type, no matter what concrete type ends
+up substituting for the generic type.
+
+We can also specify constraints on generic types when defining methods on the
+type. We could, for example, implement methods only on `Point<f32>` instances
+rather than on `Point<T>` instances with any generic type. In Listing 10-10 we
+use the concrete type `f32`, meaning we don’t declare any types after `impl`.
 
 <span class="filename">Filename: src/main.rs</span>
 
@@ -234,14 +238,14 @@ any types after `impl`.
 <span class="caption">Listing 10-10: An `impl` block that only applies to a
 struct with a particular concrete type for the generic type parameter `T`</span>
 
-This code means the type `Point<f32>` will have a method named
-`distance_from_origin` and other instances of `Point<T>` where `T` is not of
-type `f32` will not have this method defined. The method measures how far our
-point is from the point at coordinates (0.0, 0.0) and uses mathematical
-operations that are available only for floating point types.
+This code means the type `Point<f32>` will have a `distance_from_origin`
+method; other instances of `Point<T>` where `T` is not of type `f32` will not
+have this method defined. The method measures how far our point is from the
+point at coordinates (0.0, 0.0) and uses mathematical operations that are
+available only for floating point types.
 
 Generic type parameters in a struct definition aren’t always the same as those
-you use in that struct’s method signatures. Listing 10-11 uses the generic
+you use in that same struct’s method signatures. Listing 10-11 uses the generic
 types `X1` and `Y1` for the `Point` struct and `X2` `Y2` for the `mixup` method
 signature to make the example clearer. The method creates a new `Point`
 instance with the `x` value from the `self` `Point` (of type `X1`) and the `y`
@@ -253,7 +257,7 @@ value from the passed-in `Point` (of type `Y2`).
 {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-11/src/main.rs}}
 ```
 
-<span class="caption">Listing 10-11: A method that uses different generic types
+<span class="caption">Listing 10-11: A method that uses generic types different
 from its struct’s definition</span>
 
 In `main`, we’ve defined a `Point` that has an `i32` for `x` (with value `5`)
@@ -273,22 +277,19 @@ method.
 
 ### Performance of Code Using Generics
 
-You might be wondering whether there is a runtime cost when you’re using
-generic type parameters. The good news is that Rust implements generics in such
-a way that your code doesn’t run any slower using generic types than it would
-with concrete types.
+You might be wondering whether there is a runtime cost when using generic type
+parameters. The good news is that using generic types won't make your run any
+slower than it would with concrete types.
 
-Rust accomplishes this by performing monomorphization of the code that is using
+Rust accomplishes this by performing monomorphization of the code using
 generics at compile time. *Monomorphization* is the process of turning generic
 code into specific code by filling in the concrete types that are used when
-compiled.
-
-In this process, the compiler does the opposite of the steps we used to create
-the generic function in Listing 10-5: the compiler looks at all the places
-where generic code is called and generates code for the concrete types the
-generic code is called with.
+compiled. In this process, the compiler does the opposite of the steps we used
+to create the generic function in Listing 10-5: the compiler looks at all the
+places where generic code is called and generates code for the concrete types
+the generic code is called with.
 
-Let’s look at how this works with an example that uses the standard library’s
+Let’s look at how this works by using the standard library’s generic
 `Option<T>` enum:
 
 ```rust
@@ -303,8 +304,7 @@ is `f64`. As such, it expands the generic definition of `Option<T>` into
 `Option_i32` and `Option_f64`, thereby replacing the generic definition with
 the specific ones.
 
-The monomorphized version of the code looks like the following. The generic
-`Option<T>` is replaced with the specific definitions created by the compiler:
+The monomorphized version of the code looks like the following:
 
 <span class="filename">Filename: src/main.rs</span>
 
@@ -325,10 +325,12 @@ fn main() {
 }
 ```
 
-Because Rust compiles generic code into code that specifies the type in each
-instance, we pay no runtime cost for using generics. When the code runs, it
-performs just as it would if we had duplicated each definition by hand. The
-process of monomorphization makes Rust’s generics extremely efficient at
-runtime.
+The generic `Option<T>` is replaced with the specific definitions created by
+the compiler. Because Rust compiles generic code into code that specifies the
+type in each instance, we pay no runtime cost for using generics. When the code
+runs, it performs just as it would if we had duplicated each definition by
+hand. The process of monomorphization makes Rust’s generics extremely efficient
+at runtime.
 
 [traits-as-parameters]: ch10-02-traits.html#traits-as-parameters
+[fixing]: ch10-02-traits.html#fixing-the-largest-function-with-trait-bounds