I'm struggling to see how this transfers ownership. Here is my code:
let res = screenshot::take_screenshot(0);
let file = File::open("test.png").expect("Failed to open file");
let encoder = PNGEncoder::new(file);
encoder.encode(&res.into_raw(),
res.width(),
res.height(),
ColorType::RGBA(0)
);
screenshot::take_screenshot is a function that returns an ImageBuffer<Rgba<u8>, Vec<u8>>. Here is the compiler error I'm getting:
error[E0382]: use of moved value: `res`
--> src/main.rs:21:37
|
21 | encoder.encode(&res.into_raw(), res.width(), res.height(), ColorType::RGBA(0));
| --- ^^^ value used here after move
| |
| value moved here
|
= note: move occurs because `res` has type `image::ImageBuffer<image::Rgba<u8>, std::vec::Vec<u8>>`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `res`
--> src/main.rs:21:50
|
21 | encoder.encode(&res.into_raw(), res.width(), res.height(), ColorType::RGBA(0));
| --- value moved here ^^^ value used here after move
|
= note: move occurs because `res` has type `image::ImageBuffer<image::Rgba<u8>, std::vec::Vec<u8>>`, which does not implement the `Copy` trait
I am trying to pass a slice, which I believe is a reference of the vector, is it not? This would imply ownership is not passed, and the vector isn't moved. I know I'm doing something wrong and it's likely something simple.
This is simply an operator precedence issue: methods apply before the reference operator &:
&(res.into_raw()) // This
(&res).into_raw() // Not this
Calling into_raw takes ownership and the value is gone.
You could do something like this:
let w = res.width();
let h = res.height();
let r = res.into_raw();
encoder.encode(&r, w, h, ColorType::RGBA(0));
It's likely there's something nicer, but you haven't provided a MCVE so it's hard to iterate on a solution. Blindly guessing from the docs, it looks like this should work:
extern crate image;
use image::{png::PNGEncoder, ColorType, ImageBuffer, Rgba};
use std::io;
fn repro<W: io::Write>(res: ImageBuffer<Rgba<u8>, Vec<u8>>, file: W) -> Result<(), io::Error> {
let encoder = PNGEncoder::new(file);
encoder.encode(&res, res.width(), res.height(), ColorType::RGBA(0))
}
fn main() {}
Related
I am newbie in the Rust world.
As an exercise, this is the problem I am trying to solve:
fn main() {
let s = give_ownership();
println!("{}", s);
}
// Only modify the code below!
fn give_ownership() -> String {
let s = String::from("hello, world");
// Convert String to Vec
let _s = s.into_bytes();
s
}
I have gotten through. My solution works.
However, when I compile the exercise code-snippet above unchanged, I don't quite get what the compiler is telling me here, as a note below:
Compiling playground v0.0.1 (/playground)
error[E0382]: use of moved value: `s`
--> src/main.rs:12:5
|
9 | let s = String::from("hello, world");
| - move occurs because `s` has type `String`, which does not implement the `Copy` trait
10 | // Convert String to Vec
11 | let _s = s.into_bytes();
| ------------ `s` moved due to this method call
12 | s
| ^ value used here after move
|
note: this function takes ownership of the receiver `self`, which moves `s`
My guess is that the note is about the function into_bytes(). The RustDoc says this about the function:
This consumes the String, so we do not need to copy its contents.
Could someone please elaborate on this?
into_bytes() takes self (i.e. an owned self, not a reference).
This means that it takes ownership of the string it's called on. It's conceptually the same as this:
fn main() {
let s = String::from("hello");
take_string(s);
println!("{s}"); // ERROR
}
fn take_string(s: String) {}
This is useful because it allows you to turn a String into a Vec<u8>, while reusing the allocation. A String is really just a Vec<u8> with the guarantee that the bytes are valid UTF-8.
So once you write let _s = s.into_bytes(), the data that was in s has now moved to _s, so you can't return s from your function. There's nothing there.
If you just want to return the string, you can just return String::from("stuff")
I'm trying to retrieve the user's lat/lon, once, in the create function of a Yew Component, so that I can do some math and pass useful decisions to child components. I've made the Yew hook "use_geolocation()" work just fine, but that only runs in a function_component, and there doesn't appear to be any straightforward way to use that location in other components.
Then I found this neat tutorial which uses wasm_bindgen and Seed::app::orders::Orders to make a "cheap clone" of the app, and to call the Javascript functions. The bindings look like:
#[wasm_bindgen]
extern "C" {
type GeolocationCoordinates;
#[wasm_bindgen(method, getter)]
fn latitude(this: &GeolocationCoordinates) -> f64;
#[wasm_bindgen(method, getter)]
fn longitude(this: &GeolocationCoordinates) -> f64;
type GeolocationPosition;
#[wasm_bindgen(method, getter)]
fn coords(this: &GeolocationPosition) ->
GeolocationCoordinates;
}
And the function for fetching geolocation, splicing together the chunks of code from Tor Hovland's tutorial:
let (app, msg_mapper) = (orders.clone_app(), orders.msg_mapper());
let geo_callback = move |position: JsValue| {
let pos: GeolocationPosition = position.into();
let coords = pos.coords();
app.update(msg_mapper(Msg::Position(
coords.latitude(),
coords.longitude(),
)));
};
let geolocation = web_sys::window()
.expect("Unable to get browser window.")
.navigator()
.geolocation()
.expect("Unable to get geolocation.");
let geo_callback_function =
Closure::wrap(
Box::new(|pos| geo_callback(pos)) as Box<dyn Fn(JsValue)>
);
geolocation.get_current_position(
&geo_callback_function.as_ref().unchecked_ref()
).expect("Unable to get position");
geo_callback_function.forget();
I attempted this route, but found that adding the line seed = "0.9.1" into my Cargo.toml produced compile errors, something about a type mismatch between a closure in wasm_bindgen and something in seed. Included here for completeness:
error[E0283]: type annotations needed for `Closure<T>`
--> /home/djmcmath/.cargo/registry/src/github.com-1ecc6299db9ec823/seed-
0.9.1/src/browser/service/routing.rs:87:9
|
87 | let closure = Closure::new(move |event: web_sys::Event| {
| ^^^^^^^
|
= note: cannot satisfy `_: WasmClosure`
note: required by a bound in `Closure::<T>::new`
--> /home/djmcmath/.cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-
0.2.81/src/closure.rs:251:17
|
251 | T: ?Sized + WasmClosure,
| ^^^^^^^^^^^ required by this bound in `Closure::<T>::new`
help: consider giving `closure` an explicit type, where the type for type parameter
`T` is specified
|
87 | let closure: Closure<T> = Closure::new(move |event: web_sys::Event| {
| ++++++++++++
help: consider specifying the type argument in the function call
|
87 | let closure = Closure::new::<F>(move |event: web_sys::Event| {
| +++++
After beating my head against that brick wall for a while, I decided to just not use Seed, but I don't know of another way to make a "cheap clone" of the app to make the lifetimes work out correctly. Without that, I get the predictable lifetime error on the geo_callback_function:
let geo_callback_function =
Closure::wrap(
Box::new(|pos: JsValue| geo_callback(pos)) as Box<dyn Fn(JsValue)>
);
Error message:
error[E0597]: `geo_callback` does not live long enough
--> src/ferry_route.rs:213:37
|
213 | Box::new(|pos: JsValue| geo_callback(pos)) as Box<dyn Fn(JsValue)>
| ------------------------^^^^^^^^^^^^------
| | | |
| | | borrowed value does not live long enough
| | value captured here
| cast requires that `geo_callback` is borrowed for `'static`
...
221 | }
| - `geo_callback` dropped here while still borrowed
So I'm at a loss, at this point. Seems like fetching user's location would be simpler than all of this. I'm open to any path that makes any of these work. (Definition of work: I can get the user's lat/lon in the create function of a Yew Component, so that I can do some math and pass useful decisions to child components.)
Ok, I think I've got it. Or at least, I've got something that works. I'm not sure it's the most elegant solution. Basically, drop the Seed parts out of the function and just pull the coords from the JsValue, like so:
fn geo_callback(position: JsValue) {
let pos = JsCast::unchecked_into::<GeolocationPosition>(position);
let coords = pos.coords();
log::info!(
"Latitude: {}. Longitude: {}.",
coords.latitude(),
coords.longitude()
);
};
At this point, I'm pretty sure I can take those coords and do something useful with them.
The idea is to send a set of characters of a vector and let the function display the current correct guesses.
Here is my main:
fn main() {
let mut guessedLetters = vec![];
displayWord(guessedLetters);
}
And here is the function:
fn displayWord(correctGuess: Vec<char>) {
let mut currentWord = String::new();
for x in 0..5 {
currentWord.push(correctGuess[x]);
}
println!("Current guesses: {}", currentWord);
}
I don't know what I'm supposed to write inside the parameters of displayWord.
There's a couple of things wrong with your code.
The first error is pretty straight forward:
--> src/main.rs:38:25
|
38 | displayWord(guessed_Letters);
| ^^^^^^^^^^^^^^^ expected char, found enum `std::option::Option`
|
= note: expected type `std::vec::Vec<char>`
found type `std::vec::Vec<std::option::Option<char>>`
The function you wrote is expecting a vector a characters ... but you're passing it a vector of Option<char>. This is happening here:
guessed_Letters.push(line.chars().nth(0));
According to the documentation, the nth method returns an Option. The quick fix here is to unwrap the Option to get the underlying value:
guessed_Letters.push(line.chars().nth(0).unwrap());
Your next error is:
error[E0382]: use of moved value: `guessed_Letters`
--> src/main.rs:38:25
|
38 | displayWord(guessed_Letters);
| ^^^^^^^^^^^^^^^ value moved here in previous iteration of loop
|
= note: move occurs because `guessed_Letters` has type `std::vec::Vec<char>`, which does not implement the `Copy` trait
This is transferring ownership of the vector on the first iteration of the loop and the compiler is telling you that subsequent iterations would be in violation of Rust's ownership rules.
The solution here is to pass the vector by reference instead:
displayWord(&guessed_Letters);
..and your method should also accept a reference:
fn displayWord(correctGuess: &Vec<char>) {
let mut currentWord = String::new();
for x in 0..5 {
currentWord.push(correctGuess[x]);
}
println!("Current guesses: {}", currentWord);
}
This can be shortened to use a slice and still work:
fn displayWord(correctGuess: &[char]) {
I am playing with Rust, and I'm trying to access the first command line argument with this code:
use std::env;
fn main() {
let args: Vec<_> = env::args().collect();
let dir = args[1];
}
And I get this error:
error[E0507]: cannot move out of indexed content
--> src/main.rs:5:15
|
5 | let dir = args[1];
| --- ^^^^^^^ cannot move out of indexed content
| |
| hint: to prevent move, use `ref dir` or `ref mut dir`
Or in later versions of Rust:
error[E0507]: cannot move out of index of `std::vec::Vec<std::string::String>`
--> src/main.rs:5:15
|
5 | let dir = args[1];
| ^^^^^^^
| |
| move occurs because value has type `std::string::String`, which does not implement the `Copy` trait
| help: consider borrowing here: `&args[1]`
If I change it to let ref dir, it compiles, but I don't grok what's going on. Could someone explain what "indexed content" means?
When you use an index operator ([]) you get the actual object at index location. You do not get a reference, pointer or copy. Since you try to bind that object with a let binding, Rust immediately tries to move (or copy, if the Copy trait is implemented).
In your example, env::args() is an iterator of Strings which is then collected into a Vec<String>. This is an owned vector of owned strings, and owned strings are not automatically copyable.
You can use a let ref binding, but the more idiomatic alternative is to take a reference to the indexed object (note the & symbol):
use std::env;
fn main() {
let args: Vec<_> = env::args().collect();
let ref dir = &args[1];
// ^
}
Implicitly moving out of a Vec is not allowed as it would leave it in an invalid state — one element is moved out, the others are not. If you have a mutable Vec, you can use a method like Vec::remove to take a single value out:
use std::env;
fn main() {
let mut args: Vec<_> = env::args().collect();
let dir = args.remove(1);
}
See also:
What is the return type of the indexing operation?
For your particular problem, you can also just use Iterator::nth:
use std::env;
fn main() {
let dir = env::args().nth(1).expect("Missing argument");
}
The accepted answer has already given the solution. I would like to explain this problem on a semantic level as a complement.
The rule is: A borrowed value can't be moved out. See this: E0507
[] operator came from the Index trait, whose function signature is:
fn index(&self, index: I) -> &<Vec<T, A> as Index<I>>::Output
As you can see, it return a reference, not own the value. Moving it out break the rule mentioned above.
I defined an Attribute type and I have a Vec<Attribute> that I am looping over to retrieve the "best" one. This was similar to my first attempt:
#[derive(Debug)]
struct Attribute;
impl Attribute {
fn new() -> Self {
Self
}
}
fn example(attrs: Vec<Attribute>, root: &mut Attribute) {
let mut best_attr = &Attribute::new();
for a in attrs.iter() {
if is_best(a) {
best_attr = a;
}
}
*root = *best_attr;
}
// simplified for example
fn is_best(_: &Attribute) -> bool {
true
}
I had the following compile error:
error[E0507]: cannot move out of borrowed content
--> src/lib.rs:17:13
|
17 | *root = *best_attr;
| ^^^^^^^^^^ cannot move out of borrowed content
After some searching for a solution, I resolved the error by doing the following:
Adding a #[derive(Clone)] attribute to my Attribute struct
Replacing the final statement with *root = best_attr.clone();
I don't fully understand why this works, and I feel like this is a rough solution to the problem I was having. How does this resolve the error, and is this the correct way to solve this problem?
You are experiencing the basis of the Rust memory model:
every object can (and must!) be owned by only exactly one other object
most types are never implicitly copied and always moved (there are some exceptions: types that implement Copy)
Take this code for example:
let x = String::new();
let y = x;
println!("{}", x);
it generates the error:
error[E0382]: borrow of moved value: `x`
--> src/main.rs:4:20
|
3 | let y = x;
| - value moved here
4 | println!("{}", x);
| ^ value borrowed here after move
|
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
x, of type String, is not implicitly copyable, and thus has been moved into y. x cannot be used any longer.
In your code, when you write *root = *best_attr, you are first dereferencing the reference best_attr, then assigning the dereferenced value to *root. Your Attribute type is not Copy, thus this assignment should be a move.
Then, the compiler complains:
cannot move out of borrowed content
Indeed, best_attr is an immutable reference, which does not allow you to take ownership of the value behind it (it doesn't even allow modifying it). Allowing such a move would put the object owning the value behind the reference in an undefined state, which is exactly what Rust aims to prevent.
In this case, your best option is indeed to create a new object with the same value as the first one, which is exactly what the trait Clone is made for.
#[derive(Clone)] allows you to mark your structs as Clone-able, as long as all of their fields are Clone. In more complex cases, you'll have to implement the trait by hand.