I'm new to Rust and I'm trying to figure out why Rc
is behaving differently when being passed to a closure. My full code is the following:
use std::rc::Rc;
struct Something {
value: i32
}
fn main() {
let wrapped_struct = Some(Rc::new(Something { value: 1 }));
let wrapped_integer = Some(Rc::new(1));
// Case 1: This works
let works: Option<i32> = wrapped_struct.map(|i| { i.value });
// Case 2: This fails
let fails: Option<i32> = wrapped_integer.map(|i| { i });
}
The error message is:
|
13 | let fails: Option<i32> = wrapped_integer.map(|i| { i });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected i32, found struct `std::rc::Rc`
|
= note: expected type `std::option::Option<i32>`
found type `std::option::Option<std::rc::Rc<{integer}>>`
What I don't understand is why in the first closure (Case 1) I can use i
as a Something
(I'd expect Rc<Something>
) but in the second one (Case 2) I can't use i
as an i32
(I actually get an Rc<i32>
).
I appreciate any pointers to the relevant documentation. Thanks a lot!
The type of the i
in both closures is actually Rc<Something>
and Rc<i32>
respectively. Rc
can be dereferenced to access its inner data, but there are places in Rust where dereferencing happens automatically, for convenience.
In the struct case, when you write i.value
, it will automatically dereference i
to access the field. It then returns a copy of the i32
, because i32
is a Copy
type. So the type of the expression i.value
is i32
. It's as if you wrote (*i).value
, but Rust did the dereferencing for you.
In the i32
case, you are just returning the i
, which still has type Rc<i32>
. You can fix it by explicitly dereferencing:
wrapped_integer.map(|i| { *i });
See also: