Discuss classes in reference manual
Still could use work, but this is the best I've got for now.
This commit is contained in:
parent
6081eb78f9
commit
7eae2044b0
148
doc/rust.md
148
doc/rust.md
@ -1106,11 +1106,12 @@ let a: list<int> = cons(7, @cons(13, @nil));
|
||||
|
||||
### Classes
|
||||
|
||||
TODO: more about classes
|
||||
|
||||
_Classes_ are named record types that may have a destructor associated
|
||||
with them, as well as fields and methods. For historical reasons, we
|
||||
may call a class with a destructor and a single field a "resource".
|
||||
A _class_ is a named record type that collects together fields and
|
||||
methods. It must have a _constructor_ (a function called `new` that
|
||||
returns a new instance of the class), and may have a destructor (a
|
||||
nullary function called `drop` that executes before the memory manager
|
||||
frees the memory for a given class). For historical reasons, we may
|
||||
call a class with a destructor and a single field a "resource".
|
||||
|
||||
A _class item_ declares a class type:
|
||||
|
||||
@ -1123,21 +1124,130 @@ class file_descriptor {
|
||||
~~~~
|
||||
|
||||
Calling the `file_descriptor` constructor function on an integer will
|
||||
produce a value with the `file_descriptor` type. Resource types have a
|
||||
noncopyable [type kind](#type-kinds), and thus may not be
|
||||
copied. Class types that don't have destructors may be copied if all
|
||||
their fields are copyable. The semantics guarantee that for each
|
||||
constructed resource value, the destructor will run once: when the
|
||||
value is disposed of (barring drastic program termination that somehow
|
||||
prevents unwinding from taking place). For stack-allocated values,
|
||||
disposal happens when the value goes out of scope. For values in
|
||||
shared boxes, it happens when the reference count of the box reaches
|
||||
zero.
|
||||
produce a value with the `file_descriptor` type.
|
||||
|
||||
The argument or arguments to the class constructor may be stored in
|
||||
the class's named fields, and can be accessed by a field reference. In
|
||||
this case, the `file_descriptor`'s data field would be accessed like
|
||||
`f.fd`, if `f` is a value of type `file_descriptor`.
|
||||
_Fields_ are immutable by default, so instances of `file_descriptor`
|
||||
can't have their `fd` fields reassigned. A mutable field declaration
|
||||
looks like:
|
||||
|
||||
~~~~
|
||||
let mut fd: libc::c_int;
|
||||
~~~~
|
||||
|
||||
The only exception is that the body of the class constructor begins
|
||||
with all the class's fields uninitialized, and is allowed to -- in
|
||||
fact, must -- initialize all the fields. A special case in the
|
||||
typestate pass enforces this invariant.
|
||||
|
||||
Usually, the class constructor stores its argument or arguments in the
|
||||
class's named fields. In this case, the `file_descriptor`'s data field
|
||||
would be accessed like `f.fd`, if `f` is a value of type
|
||||
`file_descriptor`. By default, class fields are _public_: they can be
|
||||
accessed both from methods inside the class, and code outside the
|
||||
class. Classes can also have private fields:
|
||||
|
||||
~~~~
|
||||
class file_descriptor {
|
||||
let fd: *libc::FILE;
|
||||
new(fd: *libc::FILE) {
|
||||
self.fd = fd; self.name = none;
|
||||
}
|
||||
priv {
|
||||
let mut name: option<str>;
|
||||
}
|
||||
fn get_name() -> str {
|
||||
alt self.name {
|
||||
none { fail "File has no name!"; }
|
||||
some(n) { n }
|
||||
}
|
||||
}
|
||||
}
|
||||
~~~~
|
||||
|
||||
Private fields are instance-private: methods in a class `C` can access
|
||||
`self`'s private fields, but not private fields of other values of
|
||||
type `C`. Code outside a class can't access any private fields.
|
||||
|
||||
A class item may contain _methods_, which take an implicit `self`
|
||||
argument:
|
||||
|
||||
~~~~
|
||||
class file_descriptor {
|
||||
let fd: *libc::FILE;
|
||||
new(fd: *libc::FILE) { self.fd = fd; }
|
||||
fn flush() {
|
||||
libc::fflush(self.fd);
|
||||
}
|
||||
}
|
||||
~~~~
|
||||
|
||||
In this case, ```open``` is a nullary method that calls the
|
||||
```fopen``` function, defined in another library, on the ```fd```
|
||||
field. As in this example, methods must refer to their self's fields
|
||||
as fields of ```self```; bare references to ```fd``` can't
|
||||
occur. Methods can be public or private; just like fields, they are
|
||||
public by default and private if enclosed in a `priv` section.
|
||||
|
||||
Classes may be polymorphic:
|
||||
|
||||
~~~~
|
||||
class file<A: copy> {
|
||||
let data: A;
|
||||
let fd: *libc::FILE;
|
||||
new(data: A, fd: *libc::FILE) { self.data = data; self.fd = fd; }
|
||||
}
|
||||
~~~~
|
||||
|
||||
Methods may also be polymorphic, and can have additional type
|
||||
parameters other than those bound in the class:
|
||||
|
||||
~~~~
|
||||
class file<A: copy> {
|
||||
let data: A;
|
||||
let fd: *libc::FILE;
|
||||
new(fd: *libc::FILE, data: A) { self.fd = fd; self.data = data; }
|
||||
fn map_data<B>(f: fn(A) -> B) -> B {
|
||||
f(self.data)
|
||||
}
|
||||
}
|
||||
~~~~
|
||||
|
||||
Classes do not support inheritance, except through traits. As a
|
||||
result, all class method dispatch is static (non-virtual).
|
||||
|
||||
A class may implement a trait (see [interfaces](#interfaces)):
|
||||
|
||||
~~~~
|
||||
trait to_str {
|
||||
fn to_str() -> str;
|
||||
}
|
||||
|
||||
class file : to_str {
|
||||
let fd: *libc::FILE;
|
||||
new(fd: *libc::FILE) { self.fd = fd; }
|
||||
fn to_str() -> str { "a file" }
|
||||
}
|
||||
~~~~
|
||||
|
||||
The syntax `class file: to_str` is pronounced "class `file`
|
||||
implements trait `to_str`".
|
||||
|
||||
Class instances may be allocated on the stack, in the exchange heap,
|
||||
or on the task heap. A value with a class type ```C``` has a
|
||||
noncopyable [type kind](#type-kinds) if ```C``` has a destructor, and
|
||||
thus may not be copied. Class types that don't have destructors may be
|
||||
copied if all their fields are copyable.
|
||||
|
||||
The semantics guarantee that for each constructed resource value, the
|
||||
destructor will run once: when the value is disposed of (barring
|
||||
drastic program termination that somehow prevents unwinding from
|
||||
taking place). For stack-allocated values, disposal happens when the
|
||||
value goes out of scope. For values in shared boxes, it happens when
|
||||
the reference count of the box reaches zero.
|
||||
|
||||
The order of fields in a class instance is significant; its runtime
|
||||
representation is the same as that of a record with identical fields
|
||||
laid out in the same order.
|
||||
|
||||
### Interfaces
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user