From 6a0a885ad6f8efd1c15fb398a1d3fd2d0ceb977d Mon Sep 17 00:00:00 2001 From: nomicon-kr Date: Tue, 10 Sep 2024 15:06:26 +0900 Subject: [PATCH] Update dot-operator.md --- src/dot-operator.md | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/src/dot-operator.md b/src/dot-operator.md index da34f9a..1b23976 100644 --- a/src/dot-operator.md +++ b/src/dot-operator.md @@ -34,25 +34,17 @@ fn do_stuff(value: &T) { } ``` -What type is `cloned`? -First, the compiler checks if it can call by value. -The type of `value` is `&T`, and so the `clone` function has signature -`fn clone(&T) -> T`. -It knows that `T: Clone`, so the compiler finds that `cloned: T`. - -What would happen if the `T: Clone` restriction was removed? It 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 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 behavior is used to create some subtle -effects: +`cloned`는 어떤 타입일까요? 먼저, 컴파일러는 값으로 호출할 수 있는지 알아봅니다. `value`의 타입은 `&T`이고, `clone` 함수는 `fn clone(&T) -> T`의 시그니처를 가지고 있습니다. 컴파일러는 `T: Clone`을 알고 있으니, +`cloned: T`인 것을 찾아냅니다. + +만약 `T: Clone` 제한이 없어졌다면 무슨 일이 일어날까요? `T`를 위한 `Clone` 구현이 없으므로, 컴파일러는 값으로 호출하지 못할 것입니다. 따라서 컴파일러는 자동 참조로 호출을 시도합니다. 이 경우에는 `Self = &T`이므로 +함수는 `fn clone(&&T) -> &T`의 시그니처를 가지게 됩니다. 컴파일러는 `&T: Clone`을 알아차리고, `cloned: &T`라고 결론짓습니다. + +여기, 자동 참조 동작이 잘 보이지 않는 변화를 만들어내는 데 쓰이는, 다른 예제가 있습니다. ```rust -# use std::sync::Arc; -# +use std::sync::Arc; + #[derive(Clone)] struct Container(Arc); @@ -62,13 +54,9 @@ fn clone_containers(foo: &Container, bar: &Container) { } ``` -What types are `foo_cloned` and `bar_cloned`? -We know that `Container: Clone`, so the compiler calls `clone` by value to give -`foo_cloned: Container`. -However, `bar_cloned` actually has type `&Container`. -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): +`foo_cloned`와 `bar_cloned`는 어떤 타입일까요? 우리는 `Container: Clone`이라는 것을 알기 때문에, 컴파일러는 `clone`을 값으로 호출하여 `foo_cloned: Container`를 얻어냅니다. 그러나, +`bar_cloned`는 실제로는 `&Container`를 타입으로 가지게 됩니다. 확실히 이것은 말이 되지 않습니다 - 우리는 `Container`에 `#[derive(Clone)]`을 추가했으므로, `Container`는 `Clone`을 구현해야 합니다! +좀더 가까이 보자면, `derive` 매크로에 의해 생성된 코드는 (대강) 다음과 같습니다: ```rust,ignore impl Clone for Container where T: Clone { @@ -78,6 +66,8 @@ impl Clone for Container where T: Clone { } ``` + + The derived `Clone` implementation is [only defined where `T: Clone`][clone], so there is no implementation for `Container: Clone` for a generic `T`. The compiler then looks to see if `&Container` implements `Clone`, which it does.