Apply suggestions from code review

Co-authored-by: Yuki Okushi <jtitor@2k36.org>
pull/292/head
Thirds 4 years ago committed by GitHub
parent f4653e1234
commit d0a45b752c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -26,8 +26,9 @@ This just means that if `T` has a size parameter known at compile time, we "forg
it for the purpose of resolving methods. For instance, this unsizing step can
convert `[i32; 2]` into `[i32]` by "forgetting" the size of the array.
Here is an example of the method lookup algorithm.
```rust.ignore
Here is an example of the method lookup algorithm:
```rust,ignore
let array: Rc<Box<[T; 3]>> = ...;
let first_entry = array[0];
```
@ -38,21 +39,23 @@ trait - the compiler will convert `array[0]` into `array.index(0)`. Now, the
compiler checks to see if `array` implements `Index`, so that we can call the
function.
First, the compiler checks if `Rc<Box<[T; 3]>>` implements `Index`, but it
Then, the compiler checks if `Rc<Box<[T; 3]>>` implements `Index`, but it
does not, and neither do `&Rc<Box<[T; 3]>>` or `&mut Rc<Box<[T; 3]>>`. Since
none of these worked, the compiler dereferences the `Rc<Box<[T; 3]>>` into
`Box<[T; 3]>` and tries again. `Box<[T; 3]>`, `&Box<[T; 3]>` and `&mut Box<[T; 3]>`
`Box<[T; 3]>` and tries again. `Box<[T; 3]>`, `&Box<[T; 3]>`, and `&mut Box<[T; 3]>`
do not implement `Index`, so it dereferences again. `[T; 3]` and its autorefs
also do not implement `Index`. We can't dereference `[T; 3]`, so the compiler
unsizes it, giving `[T]`. Finally, `[T]` implements `Index`, so we can now call the
actual `index` function.
Consider the following more complicated example of the dot operator at work.
```rust.ignore
Consider the following more complicated example of the dot operator at work:
```rust
fn do_stuff<T: Clone>(value: &T) {
let cloned = value.clone();
}
```
What type is `cloned`? First, the compiler checks if we can call by value.
The type of `value` is `&T`, and so the `clone` function has signature
`fn clone(&T) -> T`. We know that `T: Clone`, so the compiler finds that
@ -60,15 +63,16 @@ The type of `value` is `&T`, and so the `clone` function has signature
What would happen if the `T: Clone` restriction was removed? We would not be able
to call by value, since there is no implementation of `Clone` for `T`. So the
compiler tries to call by autoref. In this case, the function has signature
compiler tries to call by autoref. In this case, the function has the signature
`fn clone(&&T) -> &T` since `Self = &T`. The compiler sees that `&T: Clone`, and
then deduces that `cloned: &T`.
Here is another example where the autoref behaviour is used to create some subtle
effects.
```rust.ignore
use std::sync::Arc;
Here is another example where the autoref behavior is used to create some subtle
effects:
```rust
# use std::sync::Arc;
#
#[derive(Clone)]
struct Container<T>(Arc<T>);
@ -77,11 +81,13 @@ fn clone_containers<T>(foo: &Container<i32>, bar: &Container<T>) {
let bar_cloned = bar.clone();
}
```
What types are `foo_cloned` and `bar_cloned`? We know that `Container<i32>: Clone`,
so the compiler calls `clone` by value to give `foo_cloned: Container<i32>`.
However, `bar_cloned` actually has type `&Container<T>`. Surely this doesn't make
sense - we added `#[derive(Clone)]` to `Container`, so it must implement `Clone`!
Looking closer, the code generated by the `derive` macro is (roughly)
Looking closer, the code generated by the `derive` macro is (roughly):
```rust.ignore
impl<T> Clone for Container<T> where T: Clone {
fn clone(&self) -> Self {
@ -89,6 +95,7 @@ impl<T> Clone for Container<T> where T: Clone {
}
}
```
The derived `Clone` implementation is
[only defined where `T: Clone`][clone],
so there is no implementation for `Container<T>: Clone` for a generic `T`. The
@ -96,17 +103,19 @@ compiler then looks to see if `&Container<T>` implements `Clone`, which it does.
So it deduces that `clone` is called by autoref, and so `bar_cloned` has type
`&Container<T>`.
We can fix this by implementing `Clone` manually without requiring `T: Clone`.
```rust.ignore
We can fix this by implementing `Clone` manually without requiring `T: Clone`:
```rust,ignore
impl<T> Clone for Container<T> {
fn clone(&self) -> Self {
Self(Arc::clone(&self.0))
}
}
```
Now, the type checker deduces that `bar_cloned: Container<T>`.
[fqs]: https://doc.rust-lang.org/nightly/book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation-calling-methods-with-the-same-name
[fqs]: ../book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation-calling-methods-with-the-same-name
[method_lookup]: https://rustc-dev-guide.rust-lang.org/method-lookup.html
[index]: https://doc.rust-lang.org/std/ops/trait.Index.html
[clone]: https://doc.rust-lang.org/std/clone/trait.Clone.html#derivable
[index]: ../std/ops/trait.Index.html
[clone]: ../std/clone/trait.Clone.html#derivable

Loading…
Cancel
Save