tutorial: Move method discussion after closures, before generics
/cc: #4217
This commit is contained in:
parent
af5cd341d3
commit
191b328f31
1 changed files with 136 additions and 139 deletions
275
doc/tutorial.md
275
doc/tutorial.md
|
@ -1480,145 +1480,6 @@ if favorite_crayon_name.len() > 5 {
|
|||
}
|
||||
~~~
|
||||
|
||||
# Methods
|
||||
|
||||
Methods are like functions except that they always begin with a special argument,
|
||||
called `self`,
|
||||
which has the type of the method's receiver. The
|
||||
`self` argument is like `this` in C++ and many other languages.
|
||||
Methods are called with dot notation, as in `my_vec.len()`.
|
||||
|
||||
_Implementations_, written with the `impl` keyword, can define
|
||||
methods on most Rust types, including structs and enums.
|
||||
As an example, let's define a `draw` method on our `Shape` enum.
|
||||
|
||||
~~~
|
||||
# fn draw_circle(p: Point, f: float) { }
|
||||
# fn draw_rectangle(p: Point, p: Point) { }
|
||||
struct Point {
|
||||
x: float,
|
||||
y: float
|
||||
}
|
||||
|
||||
enum Shape {
|
||||
Circle(Point, float),
|
||||
Rectangle(Point, Point)
|
||||
}
|
||||
|
||||
impl Shape {
|
||||
fn draw(&self) {
|
||||
match *self {
|
||||
Circle(p, f) => draw_circle(p, f),
|
||||
Rectangle(p1, p2) => draw_rectangle(p1, p2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let s = Circle(Point { x: 1f, y: 2f }, 3f);
|
||||
s.draw();
|
||||
~~~
|
||||
|
||||
This defines an _implementation_ for `Shape` containing a single
|
||||
method, `draw`. In most respects the `draw` method is defined
|
||||
like any other function, except for the name `self`.
|
||||
|
||||
The type of `self` is the type on which the method is implemented,
|
||||
or a pointer thereof. As an argument it is written either `self`,
|
||||
`&self`, `@self`, or `~self`.
|
||||
A caller must in turn have a compatible pointer type to call the method.
|
||||
|
||||
~~~
|
||||
# fn draw_circle(p: Point, f: float) { }
|
||||
# fn draw_rectangle(p: Point, p: Point) { }
|
||||
# struct Point { x: float, y: float }
|
||||
# enum Shape {
|
||||
# Circle(Point, float),
|
||||
# Rectangle(Point, Point)
|
||||
# }
|
||||
impl Shape {
|
||||
fn draw_borrowed(&self) { ... }
|
||||
fn draw_managed(@self) { ... }
|
||||
fn draw_owned(~self) { ... }
|
||||
fn draw_value(self) { ... }
|
||||
}
|
||||
|
||||
let s = Circle(Point { x: 1f, y: 2f }, 3f);
|
||||
|
||||
(@s).draw_managed();
|
||||
(~s).draw_owned();
|
||||
(&s).draw_borrowed();
|
||||
s.draw_value();
|
||||
~~~
|
||||
|
||||
Methods typically take a borrowed pointer self type,
|
||||
so the compiler will go to great lengths to convert a callee
|
||||
to a borrowed pointer.
|
||||
|
||||
~~~
|
||||
# fn draw_circle(p: Point, f: float) { }
|
||||
# fn draw_rectangle(p: Point, p: Point) { }
|
||||
# struct Point { x: float, y: float }
|
||||
# enum Shape {
|
||||
# Circle(Point, float),
|
||||
# Rectangle(Point, Point)
|
||||
# }
|
||||
# impl Shape {
|
||||
# fn draw_borrowed(&self) { ... }
|
||||
# fn draw_managed(@self) { ... }
|
||||
# fn draw_owned(~self) { ... }
|
||||
# fn draw_value(self) { ... }
|
||||
# }
|
||||
# let s = Circle(Point { x: 1f, y: 2f }, 3f);
|
||||
// As with typical function arguments, managed and unique pointers
|
||||
// are automatically converted to borrowed pointers
|
||||
|
||||
(@s).draw_borrowed();
|
||||
(~s).draw_borrowed();
|
||||
|
||||
// Unlike typical function arguments, the self value will
|
||||
// automatically be referenced ...
|
||||
s.draw_borrowed();
|
||||
|
||||
// ... and dereferenced
|
||||
(& &s).draw_borrowed();
|
||||
|
||||
// ... and dereferenced, and borrowed, and
|
||||
(&@~s).draw_borrowed();
|
||||
~~~
|
||||
|
||||
Implementations may also define _static_ methods,
|
||||
which don't have an explicit `self` argument.
|
||||
The `static` keyword distinguishes static methods from methods that have a `self`:
|
||||
|
||||
~~~~ {.xfail-test}
|
||||
impl Circle {
|
||||
fn area(&self) -> float { ... }
|
||||
static fn new(area: float) -> Circle { ... }
|
||||
}
|
||||
~~~~
|
||||
|
||||
> ***Note***: In the future the `static` keyword will be removed and static methods
|
||||
> will be distinguished solely by the presence or absence of the `self` argument.
|
||||
> In the current langugage instance methods may also be declared without an explicit
|
||||
> `self` argument, in which case `self` is an implicit reference.
|
||||
> That form of method is deprecated.
|
||||
|
||||
Constructors are one common application for static methods, as in `new` above.
|
||||
To call a static method, you have to prefix it with the type name and a double colon:
|
||||
|
||||
~~~~
|
||||
# use float::consts::pi;
|
||||
# use float::sqrt;
|
||||
struct Circle { radius: float }
|
||||
impl Circle {
|
||||
static fn new(area: float) -> Circle { Circle { radius: sqrt(area / pi) } }
|
||||
}
|
||||
let c = Circle::new(42.5);
|
||||
~~~~
|
||||
|
||||
We'll discuss implementations more in the context of [traits and
|
||||
generics](#generics).
|
||||
|
||||
# Closures
|
||||
|
||||
Named functions, like those we've seen so far, may not refer to local
|
||||
|
@ -1886,6 +1747,142 @@ fn contains(v: &[int], elt: int) -> bool {
|
|||
> the keywords `break`, `loop`, and `return` work, in varying degree,
|
||||
> with `while`, `loop`, `do`, and `for` constructs.
|
||||
|
||||
# Methods
|
||||
|
||||
Methods are like functions except that they always begin with a special argument,
|
||||
called `self`,
|
||||
which has the type of the method's receiver. The
|
||||
`self` argument is like `this` in C++ and many other languages.
|
||||
Methods are called with dot notation, as in `my_vec.len()`.
|
||||
|
||||
_Implementations_, written with the `impl` keyword, can define
|
||||
methods on most Rust types, including structs and enums.
|
||||
As an example, let's define a `draw` method on our `Shape` enum.
|
||||
|
||||
~~~
|
||||
# fn draw_circle(p: Point, f: float) { }
|
||||
# fn draw_rectangle(p: Point, p: Point) { }
|
||||
struct Point {
|
||||
x: float,
|
||||
y: float
|
||||
}
|
||||
|
||||
enum Shape {
|
||||
Circle(Point, float),
|
||||
Rectangle(Point, Point)
|
||||
}
|
||||
|
||||
impl Shape {
|
||||
fn draw(&self) {
|
||||
match *self {
|
||||
Circle(p, f) => draw_circle(p, f),
|
||||
Rectangle(p1, p2) => draw_rectangle(p1, p2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let s = Circle(Point { x: 1f, y: 2f }, 3f);
|
||||
s.draw();
|
||||
~~~
|
||||
|
||||
This defines an _implementation_ for `Shape` containing a single
|
||||
method, `draw`. In most respects the `draw` method is defined
|
||||
like any other function, except for the name `self`.
|
||||
|
||||
The type of `self` is the type on which the method is implemented,
|
||||
or a pointer thereof. As an argument it is written either `self`,
|
||||
`&self`, `@self`, or `~self`.
|
||||
A caller must in turn have a compatible pointer type to call the method.
|
||||
|
||||
~~~
|
||||
# fn draw_circle(p: Point, f: float) { }
|
||||
# fn draw_rectangle(p: Point, p: Point) { }
|
||||
# struct Point { x: float, y: float }
|
||||
# enum Shape {
|
||||
# Circle(Point, float),
|
||||
# Rectangle(Point, Point)
|
||||
# }
|
||||
impl Shape {
|
||||
fn draw_borrowed(&self) { ... }
|
||||
fn draw_managed(@self) { ... }
|
||||
fn draw_owned(~self) { ... }
|
||||
fn draw_value(self) { ... }
|
||||
}
|
||||
|
||||
let s = Circle(Point { x: 1f, y: 2f }, 3f);
|
||||
|
||||
(@s).draw_managed();
|
||||
(~s).draw_owned();
|
||||
(&s).draw_borrowed();
|
||||
s.draw_value();
|
||||
~~~
|
||||
|
||||
Methods typically take a borrowed pointer self type,
|
||||
so the compiler will go to great lengths to convert a callee
|
||||
to a borrowed pointer.
|
||||
|
||||
~~~
|
||||
# fn draw_circle(p: Point, f: float) { }
|
||||
# fn draw_rectangle(p: Point, p: Point) { }
|
||||
# struct Point { x: float, y: float }
|
||||
# enum Shape {
|
||||
# Circle(Point, float),
|
||||
# Rectangle(Point, Point)
|
||||
# }
|
||||
# impl Shape {
|
||||
# fn draw_borrowed(&self) { ... }
|
||||
# fn draw_managed(@self) { ... }
|
||||
# fn draw_owned(~self) { ... }
|
||||
# fn draw_value(self) { ... }
|
||||
# }
|
||||
# let s = Circle(Point { x: 1f, y: 2f }, 3f);
|
||||
// As with typical function arguments, managed and unique pointers
|
||||
// are automatically converted to borrowed pointers
|
||||
|
||||
(@s).draw_borrowed();
|
||||
(~s).draw_borrowed();
|
||||
|
||||
// Unlike typical function arguments, the self value will
|
||||
// automatically be referenced ...
|
||||
s.draw_borrowed();
|
||||
|
||||
// ... and dereferenced
|
||||
(& &s).draw_borrowed();
|
||||
|
||||
// ... and dereferenced, and borrowed, and
|
||||
(&@~s).draw_borrowed();
|
||||
~~~
|
||||
|
||||
Implementations may also define _static_ methods,
|
||||
which don't have an explicit `self` argument.
|
||||
The `static` keyword distinguishes static methods from methods that have a `self`:
|
||||
|
||||
~~~~ {.xfail-test}
|
||||
impl Circle {
|
||||
fn area(&self) -> float { ... }
|
||||
static fn new(area: float) -> Circle { ... }
|
||||
}
|
||||
~~~~
|
||||
|
||||
> ***Note***: In the future the `static` keyword will be removed and static methods
|
||||
> will be distinguished solely by the presence or absence of the `self` argument.
|
||||
> In the current langugage instance methods may also be declared without an explicit
|
||||
> `self` argument, in which case `self` is an implicit reference.
|
||||
> That form of method is deprecated.
|
||||
|
||||
Constructors are one common application for static methods, as in `new` above.
|
||||
To call a static method, you have to prefix it with the type name and a double colon:
|
||||
|
||||
~~~~
|
||||
# use float::consts::pi;
|
||||
# use float::sqrt;
|
||||
struct Circle { radius: float }
|
||||
impl Circle {
|
||||
static fn new(area: float) -> Circle { Circle { radius: sqrt(area / pi) } }
|
||||
}
|
||||
let c = Circle::new(42.5);
|
||||
~~~~
|
||||
|
||||
# Generics
|
||||
|
||||
Throughout this tutorial, we've been defining functions that act only
|
||||
|
|
Loading…
Add table
Reference in a new issue