Use explicit self in rest of tutorial

/cc: #4217
This commit is contained in:
Brian Anderson 2012-12-20 01:51:28 -08:00
parent 171e6a16f7
commit 42ab33e572
1 changed files with 45 additions and 44 deletions

View File

@ -2033,7 +2033,7 @@ console, with a single method:
~~~~ ~~~~
trait Printable { trait Printable {
fn print(); fn print(&self);
} }
~~~~ ~~~~
@ -2045,13 +2045,13 @@ and `~str`.
[impls]: #functions-and-methods [impls]: #functions-and-methods
~~~~ ~~~~
# trait Printable { fn print(); } # trait Printable { fn print(&self); }
impl int: Printable { impl int: Printable {
fn print() { io::println(fmt!("%d", self)) } fn print(&self) { io::println(fmt!("%d", *self)) }
} }
impl &str: Printable { impl &str: Printable {
fn print() { io::println(self) } fn print(&self) { io::println(*self) }
} }
# 1.print(); # 1.print();
@ -2065,14 +2065,14 @@ types might look like the following:
~~~~ ~~~~
trait Seq<T> { trait Seq<T> {
fn len() -> uint; fn len(&self) -> uint;
fn iter(b: fn(v: &T)); fn iter(&self, b: fn(v: &T));
} }
impl<T> ~[T]: Seq<T> { impl<T> ~[T]: Seq<T> {
fn len() -> uint { vec::len(self) } fn len(&self) -> uint { vec::len(*self) }
fn iter(b: fn(v: &T)) { fn iter(&self, b: fn(v: &T)) {
for vec::each(self) |elt| { b(elt); } for vec::each(*self) |elt| { b(elt); }
} }
} }
~~~~ ~~~~
@ -2096,21 +2096,22 @@ trait, `self` is a type, and in an impl, `self` is a value. The
following trait describes types that support an equality operation: following trait describes types that support an equality operation:
~~~~ ~~~~
// In a trait, `self` refers to the type implementing the trait // In a trait, `self` refers both to the self argument
// and to the type implementing the trait
trait Eq { trait Eq {
fn equals(other: &self) -> bool; fn equals(&self, other: &self) -> bool;
} }
// In an impl, `self` refers to the value of the receiver // In an impl, `self` refers just to the value of the receiver
impl int: Eq { impl int: Eq {
fn equals(other: &int) -> bool { *other == self } fn equals(&self, other: &int) -> bool { *other == *self }
} }
~~~~ ~~~~
Notice that in the trait definition, `equals` takes a parameter of Notice that in the trait definition, `equals` takes a
type `self`. In contrast, in the `impl`, `equals` takes a parameter of second parameter of type `self`.
type `int`, and uses `self` as the name of the receiver (analogous to In contrast, in the `impl`, `equals` takes a second parameter of
the `this` pointer in C++). type `int`, only using `self` as the name of the receiver.
## Bounded type parameters and static method dispatch ## Bounded type parameters and static method dispatch
@ -2120,7 +2121,7 @@ define _bounds_ on type parameters, so that we can then operate on
generic types. generic types.
~~~~ ~~~~
# trait Printable { fn print(); } # trait Printable { fn print(&self); }
fn print_all<T: Printable>(printable_things: ~[T]) { fn print_all<T: Printable>(printable_things: ~[T]) {
for printable_things.each |thing| { for printable_things.each |thing| {
thing.print(); thing.print();
@ -2138,7 +2139,7 @@ Type parameters can have multiple bounds by separating them with spaces,
as in this version of `print_all` that copies elements. as in this version of `print_all` that copies elements.
~~~ ~~~
# trait Printable { fn print(); } # trait Printable { fn print(&self); }
fn print_all<T: Printable Copy>(printable_things: ~[T]) { fn print_all<T: Printable Copy>(printable_things: ~[T]) {
let mut i = 0; let mut i = 0;
while i < printable_things.len() { while i < printable_things.len() {
@ -2163,9 +2164,9 @@ However, consider this function:
~~~~ ~~~~
# type Circle = int; type Rectangle = int; # type Circle = int; type Rectangle = int;
# impl int: Drawable { fn draw() {} } # impl int: Drawable { fn draw(&self) {} }
# fn new_circle() -> int { 1 } # fn new_circle() -> int { 1 }
trait Drawable { fn draw(); } trait Drawable { fn draw(&self); }
fn draw_all<T: Drawable>(shapes: ~[T]) { fn draw_all<T: Drawable>(shapes: ~[T]) {
for shapes.each |shape| { shape.draw(); } for shapes.each |shape| { shape.draw(); }
@ -2181,7 +2182,7 @@ needed, a trait name can alternately be used as a type, called
an _object_. an _object_.
~~~~ ~~~~
# trait Drawable { fn draw(); } # trait Drawable { fn draw(&self); }
fn draw_all(shapes: &[@Drawable]) { fn draw_all(shapes: &[@Drawable]) {
for shapes.each |shape| { shape.draw(); } for shapes.each |shape| { shape.draw(); }
} }
@ -2194,14 +2195,14 @@ value to an object:
~~~~ ~~~~
# type Circle = int; type Rectangle = bool; # type Circle = int; type Rectangle = bool;
# trait Drawable { fn draw(); } # trait Drawable { fn draw(&self); }
# fn new_circle() -> Circle { 1 } # fn new_circle() -> Circle { 1 }
# fn new_rectangle() -> Rectangle { true } # fn new_rectangle() -> Rectangle { true }
# fn draw_all(shapes: &[@Drawable]) {} # fn draw_all(shapes: &[@Drawable]) {}
impl Circle: Drawable { fn draw() { ... } } impl Circle: Drawable { fn draw(&self) { ... } }
impl Rectangle: Drawable { fn draw() { ... } } impl Rectangle: Drawable { fn draw(&self) { ... } }
let c: @Circle = @new_circle(); let c: @Circle = @new_circle();
let r: @Rectangle = @new_rectangle(); let r: @Rectangle = @new_rectangle();
@ -2218,8 +2219,8 @@ for example, an `@Circle` may not be cast to an `~Drawable`.
~~~ ~~~
# type Circle = int; type Rectangle = int; # type Circle = int; type Rectangle = int;
# trait Drawable { fn draw(); } # trait Drawable { fn draw(&self); }
# impl int: Drawable { fn draw() {} } # impl int: Drawable { fn draw(&self) {} }
# fn new_circle() -> int { 1 } # fn new_circle() -> int { 1 }
# fn new_rectangle() -> int { 2 } # fn new_rectangle() -> int { 2 }
// A managed object // A managed object
@ -2244,7 +2245,7 @@ The `static` keyword distinguishes static methods from methods that have a `self
~~~~ ~~~~
trait Shape { trait Shape {
fn area() -> float; fn area(&self) -> float;
static fn new_shape(area: float) -> Shape; static fn new_shape(area: float) -> Shape;
} }
~~~~ ~~~~
@ -2271,25 +2272,25 @@ Types that implement a trait must also implement its supertraits.
For example, we can define a `Circle` trait that only types that also have the `Shape` trait can have: For example, we can define a `Circle` trait that only types that also have the `Shape` trait can have:
~~~~ ~~~~
trait Shape { fn area() -> float; } trait Shape { fn area(&self) -> float; }
trait Circle : Shape { fn radius() -> float; } trait Circle : Shape { fn radius(&self) -> float; }
~~~~ ~~~~
Now, implementations of `Circle` methods can call `Shape` methods: Now, implementations of `Circle` methods can call `Shape` methods:
~~~~ ~~~~
# trait Shape { fn area() -> float; } # trait Shape { fn area(&self) -> float; }
# trait Circle : Shape { fn radius() -> float; } # trait Circle : Shape { fn radius(&self) -> float; }
# struct Point { x: float, y: float } # struct Point { x: float, y: float }
# use float::consts::pi; # use float::consts::pi;
# use float::sqrt; # use float::sqrt;
# fn square(x: float) -> float { x * x } # fn square(x: float) -> float { x * x }
struct CircleStruct { center: Point, radius: float } struct CircleStruct { center: Point, radius: float }
impl CircleStruct: Circle { impl CircleStruct: Circle {
fn radius() -> float { sqrt(self.area() / pi) } fn radius(&self) -> float { sqrt(self.area() / pi) }
} }
impl CircleStruct: Shape { impl CircleStruct: Shape {
fn area() -> float { pi * square(self.radius) } fn area(&self) -> float { pi * square(self.radius) }
} }
~~~~ ~~~~
@ -2301,8 +2302,8 @@ methods of the supertrait may be called on values of subtrait-bound type paramet
Refering to the previous example of `trait Circle : Shape`: Refering to the previous example of `trait Circle : Shape`:
~~~ ~~~
# trait Shape { fn area() -> float; } # trait Shape { fn area(&self) -> float; }
# trait Circle : Shape { fn radius() -> float; } # trait Circle : Shape { fn radius(&self) -> float; }
fn radius_times_area<T: Circle>(c: T) -> float { fn radius_times_area<T: Circle>(c: T) -> float {
// `c` is both a Circle and a Shape // `c` is both a Circle and a Shape
c.radius() * c.area() c.radius() * c.area()
@ -2312,10 +2313,10 @@ fn radius_times_area<T: Circle>(c: T) -> float {
Likewise, supertrait methods may also be called on trait objects. Likewise, supertrait methods may also be called on trait objects.
~~~ {.xfail-test} ~~~ {.xfail-test}
# trait Shape { fn area() -> float; } # trait Shape { fn area(&self) -> float; }
# trait Circle : Shape { fn radius() -> float; } # trait Circle : Shape { fn radius(&self) -> float; }
# impl int: Shape { fn area() -> float { 0.0 } } # impl int: Shape { fn area(&self) -> float { 0.0 } }
# impl int: Circle { fn radius() -> float { 0.0 } } # impl int: Circle { fn radius(&self) -> float { 0.0 } }
# let mycircle = 0; # let mycircle = 0;
let mycircle: Circle = @mycircle as @Circle; let mycircle: Circle = @mycircle as @Circle;
@ -2385,9 +2386,9 @@ mod farm {
// Note - visibility modifiers on impls currently have no effect // Note - visibility modifiers on impls currently have no effect
impl Farm { impl Farm {
priv fn feed_chickens() { ... } priv fn feed_chickens(&self) { ... }
priv fn feed_cows() { ... } priv fn feed_cows(&self) { ... }
fn add_chicken(c: Chicken) { ... } fn add_chicken(&self, c: Chicken) { ... }
} }
pub fn feed_animals(farm: &Farm) { pub fn feed_animals(farm: &Farm) {
@ -2407,7 +2408,7 @@ fn main() {
# enum Human = int; # enum Human = int;
# fn make_me_a_farm() -> farm::Farm { farm::make_me_a_farm() } # fn make_me_a_farm() -> farm::Farm { farm::make_me_a_farm() }
# fn make_me_a_chicken() -> Chicken { 0 } # fn make_me_a_chicken() -> Chicken { 0 }
# impl Human { fn rest() { } } # impl Human { fn rest(&self) { } }
~~~ ~~~
## Crates ## Crates