@@ -2035,28 +2035,30 @@ C++ templates.
2035
2035
2036
2036
## Traits
2037
2037
2038
- Within a generic function the operations available on generic types
2039
- are very limited. After all, since the function doesn't know what
2040
- types it is operating on, it can't safely modify or query their
2041
- values. This is where _traits_ come into play. Traits are Rust's most
2042
- powerful tool for writing polymorphic code. Java developers will see
2043
- them as similar to Java interfaces, and Haskellers will notice their
2044
- similarities to type classes. Rust's traits are a form of *bounded
2045
- polymorphism*: a trait is a way of limiting the set of possible types
2046
- that a type parameter could refer to.
2047
-
2048
- As motivation, let us consider copying in Rust.
2049
- The `clone` method is not defined for all Rust types.
2050
- One reason is user-defined destructors:
2051
- copying a type that has a destructor
2052
- could result in the destructor running multiple times.
2053
- Therefore, types with destructors cannot be copied
2054
- unless you explicitly implement `Clone` for them.
2038
+ Within a generic function -- that is, a function parameterized by a
2039
+ type parameter, say, `T` -- the operations we can do on arguments of
2040
+ type `T` are quite limited. After all, since we don't know what type
2041
+ `T` will be instantiated with, we can't safely modify or query values
2042
+ of type `T`. This is where _traits_ come into play. Traits are Rust's
2043
+ most powerful tool for writing polymorphic code. Java developers will
2044
+ see them as similar to Java interfaces, and Haskellers will notice
2045
+ their similarities to type classes. Rust's traits give us a way to
2046
+ express *bounded polymorphism*: by limiting the set of possible types
2047
+ that a type parameter could refer to, they expand the number of
2048
+ operations we can safely perform on arguments of that type.
2049
+
2050
+ As motivation, let us consider copying of values in Rust. The `clone`
2051
+ method is not defined for values of every type. One reason is
2052
+ user-defined destructors: copying a value of a type that has a
2053
+ destructor could result in the destructor running multiple times.
2054
+ Therefore, values of types that have destructors cannot be copied
2055
+ unless we explicitly implement `clone` for them.
2055
2056
2056
2057
This complicates handling of generic functions.
2057
- If you have a type parameter `T`, can you copy values of that type?
2058
- In Rust, you can't,
2059
- and if you try to run the following code the compiler will complain.
2058
+ If we have a function with a type parameter `T`,
2059
+ can we copy values of type `T` inside that function?
2060
+ In Rust, we can't,
2061
+ and if we try to run the following code the compiler will complain.
2060
2062
2061
2063
~~~~ {.xfail-test}
2062
2064
// This does not compile
@@ -2066,11 +2068,10 @@ fn head_bad<T>(v: &[T]) -> T {
2066
2068
~~~~
2067
2069
2068
2070
However, we can tell the compiler
2069
- that the `head` function is only for copyable types:
2070
- that is, those that implement the `Clone` trait.
2071
- In that case,
2072
- we can explicitly create a second copy of the value we are returning
2073
- using the `clone` keyword:
2071
+ that the `head` function is only for copyable types.
2072
+ In Rust, copyable types are those that _implement the `Clone` trait_.
2073
+ We can then explicitly create a second copy of the value we are returning
2074
+ by calling the `clone` method:
2074
2075
2075
2076
~~~~
2076
2077
// This does
@@ -2079,12 +2080,14 @@ fn head<T: Clone>(v: &[T]) -> T {
2079
2080
}
2080
2081
~~~~
2081
2082
2082
- This says that we can call `head` on any type `T`
2083
- as long as that type implements the `Clone` trait.
2083
+ The bounded type parameter `T: Clone` says that `head`
2084
+ can be called on an argument of type `&[T]` for any `T`,
2085
+ so long as there is an implementation of the
2086
+ `Clone` trait for `T`.
2084
2087
When instantiating a generic function,
2085
- you can only instantiate it with types
2088
+ we can only instantiate it with types
2086
2089
that implement the correct trait,
2087
- so you could not apply `head` to a type
2090
+ so we could not apply `head` to a vector whose elements are of some type
2088
2091
that does not implement `Clone`.
2089
2092
2090
2093
While most traits can be defined and implemented by user code,
@@ -2110,7 +2113,7 @@ have the `'static` lifetime.
2110
2113
> iterations of the language, and often still are.
2111
2114
2112
2115
Additionally, the `Drop` trait is used to define destructors. This
2113
- trait defines one method called `drop`, which is automatically
2116
+ trait provides one method called `drop`, which is automatically
2114
2117
called when a value of the type that implements this trait is
2115
2118
destroyed, either because the value went out of scope or because the
2116
2119
garbage collector reclaimed it.
@@ -2134,29 +2137,36 @@ may call it.
2134
2137
2135
2138
## Declaring and implementing traits
2136
2139
2137
- A trait consists of a set of methods without bodies,
2138
- or may be empty, as is the case with `Send` and `Freeze`.
2140
+ At its simplest, a trait is a set of zero or more _method signatures_.
2139
2141
For example, we could declare the trait
2140
2142
`Printable` for things that can be printed to the console,
2141
- with a single method:
2143
+ with a single method signature :
2142
2144
2143
2145
~~~~
2144
2146
trait Printable {
2145
2147
fn print(&self);
2146
2148
}
2147
2149
~~~~
2148
2150
2149
- Traits may be implemented for specific types with [impls]. An impl
2150
- that implements a trait includes the name of the trait at the start of
2151
- the definition, as in the following impls of `Printable` for `int`
2152
- and `~str`.
2151
+ We say that the `Printable` trait _provides_ a `print` method with the
2152
+ given signature. This means that we can call `print` on an argument
2153
+ of any type that implements the `Printable` trait.
2154
+
2155
+ Rust's built-in `Send` and `Freeze` types are examples of traits that
2156
+ don't provide any methods.
2157
+
2158
+ Traits may be implemented for specific types with [impls]. An impl for
2159
+ a particular trait gives an implementation of the methods that
2160
+ trait provides. For instance, the following impls of
2161
+ `Printable` for `int` and `~str` give implementations of the `print`
2162
+ method.
2153
2163
2154
2164
[impls]: #methods
2155
2165
2156
2166
~~~~
2157
2167
# trait Printable { fn print(&self); }
2158
2168
impl Printable for int {
2159
- fn print(&self) { println!("{}", *self) }
2169
+ fn print(&self) { println!("{:? }", *self) }
2160
2170
}
2161
2171
2162
2172
impl Printable for ~str {
@@ -2167,10 +2177,71 @@ impl Printable for ~str {
2167
2177
# (~"foo").print();
2168
2178
~~~~
2169
2179
2170
- Methods defined in an implementation of a trait may be called just like
2171
- any other method, using dot notation, as in `1.print()`. Traits may
2172
- themselves contain type parameters. A trait for generalized sequence
2173
- types might look like the following:
2180
+ Methods defined in an impl for a trait may be called just like
2181
+ any other method, using dot notation, as in `1.print()`.
2182
+
2183
+ ## Default method implementations in trait definitions
2184
+
2185
+ Sometimes, a method that a trait provides will have the same
2186
+ implementation for most or all of the types that implement that trait.
2187
+ For instance, suppose that we wanted `bool`s and `f32`s to be
2188
+ printable, and that we wanted the implementation of `print` for those
2189
+ types to be exactly as it is for `int`, above:
2190
+
2191
+ ~~~~
2192
+ # trait Printable { fn print(&self); }
2193
+ impl Printable for f32 {
2194
+ fn print(&self) { println!("{:?}", *self) }
2195
+ }
2196
+
2197
+ impl Printable for bool {
2198
+ fn print(&self) { println!("{:?}", *self) }
2199
+ }
2200
+
2201
+ # true.print();
2202
+ # 3.14159.print();
2203
+ ~~~~
2204
+
2205
+ This works fine, but we've now repeated the same definition of `print`
2206
+ in three places. Instead of doing that, we can simply include the
2207
+ definition of `print` right in the trait definition, instead of just
2208
+ giving its signature. That is, we can write the following:
2209
+
2210
+ ~~~~
2211
+ trait Printable {
2212
+ // Default method implementation
2213
+ fn print(&self) { println!("{:?}", *self) }
2214
+ }
2215
+
2216
+ impl Printable for int {}
2217
+
2218
+ impl Printable for ~str {
2219
+ fn print(&self) { println(*self) }
2220
+ }
2221
+
2222
+ impl Printable for bool {}
2223
+
2224
+ impl Printable for f32 {}
2225
+
2226
+ # 1.print();
2227
+ # (~"foo").print();
2228
+ # true.print();
2229
+ # 3.14159.print();
2230
+ ~~~~
2231
+
2232
+ Here, the impls of `Printable` for `int`, `bool`, and `f32` don't
2233
+ need to provide an implementation of `print`, because in the absence
2234
+ of a specific implementation, Rust just uses the _default method_
2235
+ provided in the trait definition. Depending on the trait, default
2236
+ methods can save a great deal of boilerplate code from having to be
2237
+ written in impls. Of course, individual impls can still override the
2238
+ default method for `print`, as is being done above in the impl for
2239
+ `~str`.
2240
+
2241
+ ## Type-parameterized traits
2242
+
2243
+ Traits may be parameterized by type variables. For example, a trait
2244
+ for generalized sequence types might look like the following:
2174
2245
2175
2246
~~~~
2176
2247
trait Seq<T> {
@@ -3023,7 +3094,7 @@ they model most closely what people expect to shadow.
3023
3094
3024
3095
## Package ids
3025
3096
3026
- If you use ` extern mod ` , per default ` rustc ` will look for libraries in the the library search path (which you can
3097
+ If you use ` extern mod ` , per default ` rustc ` will look for libraries in the library search path (which you can
3027
3098
extend with the ` -L ` switch).
3028
3099
3029
3100
However, Rust also ships with rustpkg, a package manager that is able to automatically download and build
0 commit comments