diff options
| author | bors <bors@rust-lang.org> | 2015-04-25 03:43:31 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2015-04-25 03:43:31 +0000 |
| commit | a40261ac91dd80b21830cc94de6132744e0c5078 (patch) | |
| tree | 023666901a4f040367389290d46a22c97ae7d8ce /src/doc/trpl | |
| parent | f9e53c7f2c8285f3422ac7ac091349ce572c4baa (diff) | |
| parent | 23b1d172a8245f810f179d939488325fff005158 (diff) | |
| download | rust-a40261ac91dd80b21830cc94de6132744e0c5078.tar.gz rust-a40261ac91dd80b21830cc94de6132744e0c5078.zip | |
Auto merge of #24798 - steveklabnik:rollup, r=steveklabnik
- Successful merges: #24662, #24722, #24725, #24729, #24736, #24749, #24751, #24766, #24769, #24772, #24775, #24790 - Failed merges: #24760
Diffstat (limited to 'src/doc/trpl')
| -rw-r--r-- | src/doc/trpl/SUMMARY.md | 2 | ||||
| -rw-r--r-- | src/doc/trpl/deref-coercions.md | 118 | ||||
| -rw-r--r-- | src/doc/trpl/method-syntax.md | 8 | ||||
| -rw-r--r-- | src/doc/trpl/mutability.md | 178 | ||||
| -rw-r--r-- | src/doc/trpl/operators-and-overloading.md | 82 |
5 files changed, 380 insertions, 8 deletions
diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index 7ce74e86fef..695dc42cb64 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -36,7 +36,6 @@ * [Strings](strings.md) * [Generics](generics.md) * [Traits](traits.md) - * [Operators and Overloading](operators-and-overloading.md) * [Drop](drop.md) * [if let](if-let.md) * [Trait Objects](trait-objects.md) @@ -50,6 +49,7 @@ * [Casting between types](casting-between-types.md) * [Associated Types](associated-types.md) * [Unsized Types](unsized-types.md) + * [Operators and Overloading](operators-and-overloading.md) * [Deref coercions](deref-coercions.md) * [Macros](macros.md) * [Raw Pointers](raw-pointers.md) diff --git a/src/doc/trpl/deref-coercions.md b/src/doc/trpl/deref-coercions.md index afacd304055..b7011100971 100644 --- a/src/doc/trpl/deref-coercions.md +++ b/src/doc/trpl/deref-coercions.md @@ -1,3 +1,119 @@ % `Deref` coercions -Coming soon! +The standard library provides a special trait, [`Deref`][deref]. It’s normally +used to overload `*`, the dereference operator: + +```rust +use std::ops::Deref; + +struct DerefExample<T> { + value: T, +} + +impl<T> Deref for DerefExample<T> { + type Target = T; + + fn deref(&self) -> &T { + &self.value + } +} + +fn main() { + let x = DerefExample { value: 'a' }; + assert_eq!('a', *x); +} +``` + +[deref]: ../std/ops/trait.Deref.html + +This is useful for writing custom pointer types. However, there’s a language +feature related to `Deref`: ‘deref coercions’. Here’s the rule: If you have a +type `U`, and it implements `Deref<Target=T>`, values of `&U` will +automatically coerce to a `&T`. Here’s an example: + +```rust +fn foo(s: &str) { + // borrow a string for a second +} + +// String implements Deref<Target=str> +let owned = "Hello".to_string(); + +// therefore, this works: +foo(&owned); +``` + +Using an ampersand in front of a value takes a reference to it. So `owned` is a +`String`, `&owned` is an `&String`, and since `impl Deref<Target=str> for +String`, `&String` will deref to `&str`, which `foo()` takes. + +That’s it. This rule is one of the only places in which Rust does an automatic +conversion for you, but it adds a lot of flexibility. For example, the `Rc<T>` +type implements `Deref<Target=T>`, so this works: + +```rust +use std::rc::Rc; + +fn foo(s: &str) { + // borrow a string for a second +} + +// String implements Deref<Target=str> +let owned = "Hello".to_string(); +let counted = Rc::new(owned); + +// therefore, this works: +foo(&counted); +``` + +All we’ve done is wrap our `String` in an `Rc<T>`. But we can now pass the +`Rc<String>` around anywhere we’d have a `String`. The signature of `foo` +didn’t change, but works just as well with either type. This example has two +conversions: `Rc<String>` to `String` and then `String` to `&str`. Rust will do +this as many times as possible until the types match. + +Another very common implementation provided by the standard library is: + +```rust +fn foo(s: &[i32]) { + // borrow a slice for a second +} + +// Vec<T> implements Deref<Target=[T]> +let owned = vec![1, 2, 3]; + +foo(&owned); +``` + +Vectors can `Deref` to a slice. + +## Deref and method calls + +`Deref` will also kick in when calling a method. In other words, these are +the same two things in Rust: + +```rust +struct Foo; + +impl Foo { + fn foo(&self) { println!("Foo"); } +} + +let f = Foo; + +f.foo(); +``` + +Even though `f` isn’t a reference, and `foo` takes `&self`, this works. +That’s because these things are the same: + +```rust,ignore +f.foo(); +(&f).foo(); +(&&f).foo(); +(&&&&&&&&f).foo(); +``` + +A value of type `&&&&&&&&&&&&&&&&Foo` can still have methods defined on `Foo` +called, because the compiler will insert as many * operations as necessary to +get it right. And since it’s inserting `*`s, that uses `Deref`. diff --git a/src/doc/trpl/method-syntax.md b/src/doc/trpl/method-syntax.md index 5853f3d679c..1445d39fe87 100644 --- a/src/doc/trpl/method-syntax.md +++ b/src/doc/trpl/method-syntax.md @@ -18,7 +18,7 @@ foo.bar().baz(); Luckily, as you may have guessed with the leading question, you can! Rust provides the ability to use this ‘method call syntax’ via the `impl` keyword. -## Method calls +# Method calls Here’s how it works: @@ -83,7 +83,7 @@ impl Circle { } ``` -## Chaining method calls +# Chaining method calls So, now we know how to call a method, such as `foo.bar()`. But what about our original example, `foo.bar().baz()`? This is called ‘method chaining’, and we @@ -127,7 +127,7 @@ fn grow(&self) -> Circle { We just say we’re returning a `Circle`. With this method, we can grow a new circle to any arbitrary size. -## Static methods +# Static methods You can also define methods that do not take a `self` parameter. Here’s a pattern that’s very common in Rust code: @@ -158,7 +158,7 @@ This ‘static method’ builds a new `Circle` for us. Note that static methods are called with the `Struct::method()` syntax, rather than the `ref.method()` syntax. -## Builder Pattern +# Builder Pattern Let’s say that we want our users to be able to create Circles, but we will allow them to only set the properties they care about. Otherwise, the `x` diff --git a/src/doc/trpl/mutability.md b/src/doc/trpl/mutability.md index ccb03c7f85f..e7506dfe4fd 100644 --- a/src/doc/trpl/mutability.md +++ b/src/doc/trpl/mutability.md @@ -1,3 +1,179 @@ % Mutability -Coming Soon +Mutability, the ability to change something, works a bit differently in Rust +than in other languages. The first aspect of mutability is its non-default +status: + +```rust,ignore +let x = 5; +x = 6; // error! +``` + +We can introduce mutability with the `mut` keyword: + +```rust +let mut x = 5; + +x = 6; // no problem! +``` + +This is a mutable [variable binding][vb]. When a binding is mutable, it means +you’re allowed to change what the binding points to. So in the above example, +it’s not so much that the value at `x` is changing, but that the binding +changed from one `i32` to another. + +[vb]: variable-bindings.html + +If you want to change what the binding points to, you’ll need a [mutable reference][mr]: + +```rust +let mut x = 5; +let y = &mut x; +``` + +[mr]: references-and-borrowing.html + +`y` is an immutable binding to a mutable reference, which means that you can’t +bind `y` to something else (`y = &mut z`), but you can mutate the thing that’s +bound to `y`. (`*y = 5`) A subtle distinction. + +Of course, if you need both: + +```rust +let mut x = 5; +let mut y = &mut x; +``` + +Now `y` can be bound to another value, and the value it’s referencing can be +changed. + +It’s important to note that `mut` is part of a [pattern][pattern], so you +can do things like this: + +```rust +let (mut x, y) = (5, 6); + +fn foo(mut x: i32) { +# } +``` + +[pattern]: patterns.html + +# Interior vs. Exterior Mutability + +However, when we say something is ‘immutable’ in Rust, that doesn’t mean that +it’s not able to be changed: We mean something has ‘exterior mutability’. Consider, +for example, [`Arc<T>`][arc]: + +```rust +use std::sync::Arc; + +let x = Arc::new(5); +let y = x.clone(); +``` + +[arc]: ../std/sync/struct.Arc.html + +When we call `clone()`, the `Arc<T>` needs to update the reference count. Yet +we’ve not used any `mut`s here, `x` is an immutable binding, and we didn’t take +`&mut 5` or anything. So what gives? + +To this, we have to go back to the core of Rust’s guiding philosophy, memory +safety, and the mechanism by which Rust guarantees it, the +[ownership][ownership] system, and more specifically, [borrowing][borrowing]: + +> You may have one or the other of these two kinds of borrows, but not both at +> the same time: +> +> * 0 to N references (`&T`) to a resource. +> * exactly one mutable reference (`&mut T`) + +[ownership]: ownership.html +[borrowing]: borrowing.html#The-Rules + +So, that’s the real definition of ‘immutability’: is this safe to have two +pointers to? In `Arc<T>`’s case, yes: the mutation is entirely contained inside +the structure itself. It’s not user facing. For this reason, it hands out `&T` +with `clone()`. If it handed out `&mut T`s, though, that would be a problem. + +Other types, like the ones in the [`std::cell`][stdcell] module, have the +opposite: interior mutability. For example: + +```rust +use std::cell::RefCell; + +let x = RefCell::new(42); + +let y = x.borrow_mut(); +``` + +[stdcell]: ../std/cell/index.html + +RefCell hands out `&mut` references to what’s inside of it with the +`borrow_mut()` method. Isn’t that dangerous? What if we do: + +```rust,ignore +use std::cell::RefCell; + +let x = RefCell::new(42); + +let y = x.borrow_mut(); +let z = x.borrow_mut(); +# (y, z); +``` + +This will in fact panic, at runtime. This is what `RefCell` does: it enforces +Rust’s borrowing rules at runtime, and `panic!`s if they’re violated. This +allows us to get around another aspect of Rust’s mutability rules. Let’s talk +about it first. + +## Field-level mutability + +Mutabilty is a property of either a borrow (`&mut`) or a binding (`let mut`). +This means that, for example, you cannot have a [`struct`][struct] with +some fields mutable and some immutable: + +```rust,ignore +struct Point { + x: i32, + mut y: i32, // nope +} +``` + +The mutability of a struct is in its binding: + +```rust,ignore +struct Point { + x: i32, + y: i32, +} + +let mut a = Point { x: 5, y: 6 }; + +a.x = 10; + +let b = Point { x: 5, y: 6}; + +b.x = 10; // error: cannot assign to immutable field `b.x` +``` + +[struct]: structs.html + +However, by using `Cell<T>`, you can emulate field-level mutability: + +``` +use std::cell::Cell; + +struct Point { + x: i32, + y: Cell<i32>, +} + +let mut point = Point { x: 5, y: Cell::new(6) }; + +point.y.set(7); + +println!("y: {:?}", point.y); +``` + +This will print `y: Cell { value: 7 }`. We’ve successfully updated `y`. diff --git a/src/doc/trpl/operators-and-overloading.md b/src/doc/trpl/operators-and-overloading.md index f6f9d5cae19..6a594659c37 100644 --- a/src/doc/trpl/operators-and-overloading.md +++ b/src/doc/trpl/operators-and-overloading.md @@ -1,3 +1,83 @@ % Operators and Overloading -Coming soon! +Rust allows for a limited form of operator overloading. There are certain +operators that are able to be overloaded. To support a particular operator +between types, there’s a specific trait that you can implement, which then +overloads the operator. + +For example, the `+` operator can be overloaded with the `Add` trait: + +```rust +use std::ops::Add; + +#[derive(Debug)] +struct Point { + x: i32, + y: i32, +} + +impl Add for Point { + type Output = Point; + + fn add(self, other: Point) -> Point { + Point { x: self.x + other.x, y: self.y + other.y } + } +} + +fn main() { + let p1 = Point { x: 1, y: 0 }; + let p2 = Point { x: 2, y: 3 }; + + let p3 = p1 + p2; + + println!("{:?}", p3); +} +``` + +In `main`, we can use `+` on our two `Point`s, since we’ve implemented +`Add<Output=Point>` for `Point`. + +There are a number of operators that can be overloaded this way, and all of +their associated traits live in the [`std::ops`][stdops] module. Check out its +documentation for the full list. + +[stdops]: ../std/ops/index.html + +Implementing these traits follows a pattern. Let’s look at [`Add`][add] in more +detail: + +```rust +# mod foo { +pub trait Add<RHS = Self> { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} +# } +``` + +[add]: ../std/ops/trait.Add.html + +There’s three types in total involved here: the type you `impl Add` for, `RHS`, +which defaults to `Self`, and `Output`. For an expression `let z = x + y`, `x` +is the `Self` type, `y` is the RHS, and `z` is the `Self::Output` type. + +```rust +# struct Point; +# use std::ops::Add; +impl Add<i32> for Point { + type Output = f64; + + fn add(self, rhs: i32) -> f64 { + // add an i32 to a Point and get an f64 +# 1.0 + } +} +``` + +will let you do this: + +```rust,ignore +let p: Point = // ... +let x: f64 = p + 2i32; +``` |
