It’s true that the type of &flameobject_blueprints.unwrap()
is also &Settings
. (Let’s call blue_flame_common::structures::flameobject::Settings
just Settings
to be concise.) That’s why you aren’t seening a mismatched types
error. The error has nothing to do with whether or not “&flameobject_blueprints.unwrap()
is a reference”.
Instead, well let’s start with what Rust is telling us. The full error message (which by the way you did not cite completely) probably looks something like
error[E0507]: cannot move out of `flameobject_blueprints`, a captured variable in an `FnMut` closure
--> src/…
663 | egui_plugin.ui(|ctx|
| ^^^^^ `flameobject_blueprints` is moved here
...
1207 | println!("{:?}", &flameobject_blueprints.unwrap());
| ----------------------
| |
| variable moved due to use in closure
| move occurs because `flameobject_blueprints` has type `std::option::Option<blue_flame_common::structures::flameobject::Settings>`, which does not implement the `Copy` trait
For more information about this error, try `rustc --explain E0507`.
I’d still be interested in seeing the actual full error message, and perhaps also what the Rust compiler version you were using is, and what the full relevant part of the source code looks like… since my attempt to create a similar error message resulted in far more useful results such as to following which already comes with the corresponding hint to add an as_ref()
call.
error[E0507]: cannot move out of `flameobject_blueprints`, a captured variable in an `FnMut` closure
--> <source>:12:27
|
4 | let flameobject_blueprints;
| ---------------------- captured outer variable
...
9 | egui_plugin.ui(|ctx| {
| ----- captured by this `FnMut` closure
...
12 | println!("{:?}", &flameobject_blueprints.unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^ -------- `flameobject_blueprints` moved due to this method call
| |
| help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
| move occurs because `flameobject_blueprints` has type `Option<Settings>`, which does not implement the `Copy` trait
|
note: `Option::<T>::unwrap` takes ownership of the receiver `self`, which moves `flameobject_blueprints`
--> /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/core/src/option.rs:932:25
error: aborting due to previous error
For more information about this error, try `rustc --explain E0507`.
In any case, as a first step of understanding what the error is, we should probably not be trying to re-invent the wheel in a forum, but look at the hint the compiler gives us (even for your compiler output, this part will be there): For more information about this error, try `rustc --explain E0507`
.
Running this (or visiting the corresponding online version) gives useful information:
For example, there’s the information that implementing Copy
is not the only possible approach to resolve the problem
To fix this error, you have three choices:
- Try to avoid moving the variable.
- Somehow reclaim the ownership.
- Implement the `Copy' trait on the type.
There’s also the acknowledgement (though no examples) for that this can happen when closures are involved
This can also happen when using a type implementing Fn
or FnMut
, as neither allows moving out of them (they usually represent closures which can be called more than once). Much of the text following applies equally well to non-FnOnce
closure bodies.
And in the end, there’s also a good link to more general learning resources about ownership and borrowing
For more information on Rust's ownership system, take a look at the References & Borrowing section of the Book.
Now with this out of the way, let’s address the concrete error at hand: The problem lies in unwrap
which is a fn(self)
method of Option
, expecting an argument by-value (i.e. by move
, for non-Copy
types). Calling flameobject_blueprints.unwrap()
in the closure that does not have ownership of flameobject_blueprints
will result in an error.
Writing &flameobject_blueprints.unwrap()
will not change anything about this.
First note the precedence of the operators: This expression means &(flameobject_blueprints.unwrap())
, not (&flameobject_blueprints).unwrap()
, so we are still trying to pass flameobject_blueprints
by-value (i.e. moving its ownership) to the unwrap
call, even if the result of that call is then only accessed by-reference.
Secondly, note that unwrapping an Option by-reference, is a common thing to do, but does not have its own method. Instead the combination of as_ref
(or as_mut
) with unwrap
is used. This works fine because as_ref
is a fn(&self)
method of Option
, not an fn(self)
one. The result is a new Option
, this time of type Option<&Settings>
, which you can then, subsequently, unwrap by-value if you want to.
Note that the &
you still have is redundant now. Writing &flameobject_blueprints.as_ref().unwrap()
will create a reference to a reference, of type &&Settings
, which can then be implicitly coerced back into a &Settings
reference, which is why the additional &
creates no issues here, but writing just flameobject_blueprints.as_ref().unwrap()
should be enough.