I have currently a little understanding problem regarding the dereference operator "*" in Rust.
I've learned that when x is a non-pointer type *x desugars to *std::ops::Deref::deref(&x) or *std::ops::DerefMut::deref_mut(&mut x) - depending on the context as you can read here. Both methods return an according reference: &T or &mut T.
... but when the deref methods return references, then how is it possible that you can move an inner value out of these references by unwrapping the value via the *-operator? Which is, as we know, a very common concept in Rust.
Is this some kind of special case or why and how does this work?
I see. Is eg std::sync::MutexGuard also one of these special cases? When I dereference it, it also gives me the inner value, despite it's deref implementation... should this be the case, everything makes sense again to me.
You’re presumably basing your question about MutexGuard on some example code you tested, which you might want to share if you want a more precise description of what’s actually going on there… as for special cases, no Box is the only one, other than that you can never move out of a dereferenced value. The other case of Copy types applies more generally, depending on the target type, i.e. also for a MutexGuard for something like e.g. a Mutex<i32> (since i32 is Copy) in that you wouldn’t ever actually move the value out of such a guard, but instead, copy it.
The other possibility is that you aren’t doing a move in the first place. See e.g. the definition of the concept of “place expression context” here for some contexts, where using *foo in an expression might not actually move *foo at all. Typical examples are e.g. things like *foo < … or *foo += … operators (or of course cases where a reference is taken again, etc…)
which is the actual type of y at this point. With the deref, you get:
You will note that in both cases, y is an exclusive reference to something, and thus it's not been moved out.
In your version of print_type_of, Rust has applied one of the deref coercion rules for references - "From &mut T to &U when T: Deref<Target=U>" - and then you're printing the type of T, having taken &T as an argument. Rust thus strips off the & before printing the type.
That's exactly it! I thought that due to the dereference operation the value gets moved out first before creating the mutable reference but it seems as if Rust is obviously smart enough to derive from the context that this isn't necessary at all!
Expressions that you get by dereferencing a reference are places – taking their address just yields the reference. (The same is true for eg. local variables: if you take the address of a local variable, you predictably always get a reference to that variable, its value doesn't get magically moved, because it's a place.) Referencing and de-referencing are inverse operations (as their names imply).
Well, as far as I understand x.lock().unwrap() is a value expression in a place context here. The docs say that a temporary is usually created in such cases. My assumption was that the value gets moved into this temporary but it seems that's obviously not the case here...
That doesn't matter. The returned lock guard has a Deref impl, and it returns a reference to the inner value. (How exactly it achieves that is nobody else's business.) Basically, the mutex guard is a smart pointer. And when dereferencing a pointer, *ptr is always, unconditionally a place. It doesn't matter where you got the pointer from. It's just an address. It doesn't matter whether address 0xf00b4r comes from a temporary or anyhwere else – the location it designates is always a place.
Again, this is basically impossible. If this were true, the Mutex would have no value after the guard is dropped.
(I can technically imagine degenerate mutex guard impls that do this, ie. move back and forth between themselves and the mutex, but that would violate a lot of assumptions about the value being in the mutex, which is a recipe for disaster especially in unsafe code. Not to mention that it would not generalize to RwLockGuard, since there can be more than one read guards at the same time.)