@@ -2035,28 +2035,30 @@ C++ templates.
20352035
20362036## Traits
20372037
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.
20552056
20562057This 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.
20602062
20612063~~~~ {.xfail-test}
20622064// This does not compile
@@ -2066,11 +2068,10 @@ fn head_bad<T>(v: &[T]) -> T {
20662068~~~~
20672069
20682070However, 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:
20742075
20752076~~~~
20762077// This does
@@ -2079,12 +2080,13 @@ fn head<T: Clone>(v: &[T]) -> T {
20792080}
20802081~~~~
20812082
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` is polymorphic
2084+ over any type `T`, so long as there is an implementation of the
2085+ `Clone` trait for that type.
20842086When instantiating a generic function,
2085- you can only instantiate it with types
2087+ we can only instantiate it with types
20862088that implement the correct trait,
2087- so you could not apply `head` to a type
2089+ so we could not apply `head` to a vector whose elements are of some type
20882090that does not implement `Clone`.
20892091
20902092While most traits can be defined and implemented by user code,
@@ -2110,7 +2112,7 @@ have the `'static` lifetime.
21102112> iterations of the language, and often still are.
21112113
21122114Additionally, the `Drop` trait is used to define destructors. This
2113- trait defines one method called `drop`, which is automatically
2115+ trait provides one method called `drop`, which is automatically
21142116called when a value of the type that implements this trait is
21152117destroyed, either because the value went out of scope or because the
21162118garbage collector reclaimed it.
@@ -2134,43 +2136,110 @@ may call it.
21342136
21352137## Declaring and implementing traits
21362138
2137- A trait consists of a set of methods without bodies,
2138- or may be empty, as is the case with `Send` and `Freeze`.
2139+ At its simplest, a trait is a set of zero or more _method signatures_.
21392140For example, we could declare the trait
21402141`Printable` for things that can be printed to the console,
2141- with a single method:
2142+ with a single method signature :
21422143
21432144~~~~
21442145trait Printable {
21452146 fn print(&self);
21462147}
21472148~~~~
21482149
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`.
2150+ We say that the `Printable` trait _provides_ a `print` method with the
2151+ given signature. This means that we can call `print` on an argument
2152+ of any type that implements the `Printable` trait.
2153+
2154+ Rust's built-in `Send` and `Freeze` types are examples of traits that
2155+ don't provide any methods.
2156+
2157+ Traits may be implemented for specific types with [impls]. An impl for
2158+ a particular trait gives an implementation of the methods that that
2159+ trait provides. For instance, the following the following impls of
2160+ `Printable` for `int` and `~str` give implementations of the `print`
2161+ method.
21532162
21542163[impls]: #methods
21552164
21562165~~~~
21572166# trait Printable { fn print(&self); }
21582167impl Printable for int {
2159- fn print(&self) { println!("{}", *self) }
2168+ fn print(&self) { println!("{:?}", *self) }
2169+ }
2170+
2171+ impl Printable for ~str {
2172+ fn print(&self) { println(*self) }
2173+ }
2174+
2175+ # 1.print();
2176+ # (~"foo").print();
2177+ ~~~~
2178+
2179+ Methods defined in an impl for a trait may be called just like
2180+ any other method, using dot notation, as in `1.print()`.
2181+
2182+ ## Default method implementations in trait definitions
2183+
2184+ Sometimes, a method that a trait provides will have the same
2185+ implementation for most or all of the types that implement that trait.
2186+ For instance, suppose that we wanted `bool`s and `float`s to be
2187+ printable, and that we wanted the implementation of `print` for those
2188+ types to be exactly as it is for `int`, above:
2189+
2190+ ~~~~
2191+ impl Printable for float {
2192+ fn print(&self) { println!("{:?}", *self) }
2193+ }
2194+
2195+ impl Printable for bool {
2196+ fn print(&self) { println!("{:?}", *self) }
21602197}
21612198
2199+ # true.print();
2200+ # 3.14159.print();
2201+ ~~~~
2202+
2203+ This works fine, but we've now repeated the same definition of `print`
2204+ in three places. Instead of doing that, we can simply include the
2205+ definition of `print` right in the trait definition, instead of just
2206+ giving its signature. That is, we can write the following:
2207+
2208+ ~~~~
2209+ trait Printable {
2210+ // Default method implementation
2211+ fn print(&self) { println!("{:?}", *self) }
2212+ }
2213+
2214+ impl Printable for int {}
2215+
21622216impl Printable for ~str {
21632217 fn print(&self) { println(*self) }
21642218}
21652219
2220+ impl Printable for bool {}
2221+
2222+ impl Printable for float {}
2223+
21662224# 1.print();
21672225# (~"foo").print();
2226+ # true.print();
2227+ # 3.14159.print();
21682228~~~~
21692229
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:
2230+ Here, the impls of `Printable` for `int`, `bool`, and `float` don't
2231+ need to provide an implementation of `print`, because in the absence
2232+ of a specific implementation, Rust just uses the _default method_
2233+ provided in the trait definition. Depending on the trait, default
2234+ methods can save a great deal of boilerplate code from having to be
2235+ written in impls. Of course, individual impls can still override the
2236+ default method for `print`, as is being done above in the impl for
2237+ `~str`.
2238+
2239+ ## Type-parameterized traits
2240+
2241+ Traits may be parameterized by type variables. For example, a trait
2242+ for generalized sequence types might look like the following:
21742243
21752244~~~~
21762245trait Seq<T> {
0 commit comments