I am attempting to iterate through a Vec<String> of file paths and read the content of the files. However, the match statement throws a compiler error regarding the variable in the pattern. The following is the code:
//paths: Vec<String>
//get counts in paths
for path in paths.iter() {
let mut path_result: Result<std::fs::File, std::io::Error>;
let file: std::fs::File;
if path != "-" {
path_result = std::fs::File::open(&path);
}
//match result with error
match path_result {
Ok(path_file) => { file = path_file },
Err(e) => {
match e.kind() {
std::io::ErrorKind::NotFound => { println!("{}: No such file or directory", &path) },
std::io::ErrorKind::PermissionDenied => { println!("{}: Permission denied", &path) },
_ => {
println!("{}: Unknown error", &path);
panic!("unknown error opening file");
}
}
continue;
}
};
/*get content from file variable*/
}
This is the compiler error I receive:
error[E0382]: use of moved value
--> src/main.rs:60:16
|
51 | let mut path_result: Result<std::fs::File, std::io::Error>;
| --------------- move occurs because `path_result` has type `std::result::Result<File, std::io::Error>`, which does not implement the `Copy` trait
...
60 | Ok(path_file) => { file = path_file },
| ^^^^^^^^^ value used here after move
...
75 | }
| -
| |
| value moved here, in previous iteration of loop
| value moved here, in previous iteration of loop
error: aborting due to previous error; 16 warnings emitted
For more information about this error, try `rustc --explain E0382`.
error: could not compile `test`
To learn more, run the command again with --verbose.
The warnings are in regards to unused variables not included in this snippet.
I have attempted borrowing the path_file variable's contents, but receive the same error. My understanding of the situation is that, because neither path_file nor path_result are used later in the for block and path_result is rebinded at the start, there should be no issue even if the ownership goes out of scope past the match statement. However, that seems to not be the case.
You cannot use uninitialized values in Rust. This code does not work:
// declare path_result here
let mut path_result: Result<std::fs::File, std::io::Error>;
// conditionally initialize it here
if path != "-" {
path_result = std::fs::File::open(&path);
}
// potentially use uninitialized value: error!
match path_result {
The code above is also why you're getting the value moved here, in previous iteration of the loop error, because you're not actually initializing path_result in every iteration of the loop. Once you refactor the code to unconditionally initialize path_result in every iteration then it compiles:
fn example(paths: Vec<String>) {
for path in paths.iter() {
if path == "-" {
println!("skipping un-openable path: -");
continue;
}
let file = match std::fs::File::open(&path) {
Ok(path_file) => path_file,
Err(e) => {
match e.kind() {
std::io::ErrorKind::NotFound => {
println!("{}: No such file or directory", &path)
}
std::io::ErrorKind::PermissionDenied => {
println!("{}: Permission denied", &path)
}
_ => {
println!("{}: Unknown error", &path);
panic!("unknown error opening file");
}
}
continue;
}
};
/* get content from file variable */
}
}
playground
Related
I wrote this code and it works. But I have a custom class for outputting logs to stdout. I want to call my logging function if I get an Error instead of panic! macro.
fn create_logfile() -> File {
let timestamp = Log::format_date(chrono::Local::now());
let filename = format!("{}.log", timestamp);
let logfile = match File::create(filename) {
Ok(file) => file,
Err(error) => {
panic!("There was a problem creating the file: {:?}", error)
}
};
logfile
}
For example I want get something like that:
let logfile = match File::create(filename) {
Ok(file) => file,
Err(e) => {
Log::error("Log file creation failed, reason: {}", e);
process::exit(1)
}
};
But compiler says:
[E0308] `match` arms have incompatible types.
[Note] expected struct `File`, found `()
How can I solve this problem?
If I put the error data to stderr will it help?
Your revised example with std::process::exit() works for me: (link)
use chrono; // 0.4.23
use std::fs::File;
use log; // 0.4.17
struct Log { }
impl Log {
fn format_date(date: chrono::DateTime<chrono::offset::Local>) -> i64 {
return 0;
}
}
fn old_create_logfile() -> File {
let timestamp = Log::format_date(chrono::Local::now());
let filename = format!("{}.log", timestamp);
let logfile = match File::create(filename) {
Ok(file) => file,
Err(error) => {
panic!("There was a problem creating the file: {:?}", error)
}
};
logfile
}
fn new_create_logfile() -> File {
let timestamp = Log::format_date(chrono::Local::now());
let filename = format!("{}.log", timestamp);
let logfile = match File::create(filename) {
Ok(file) => file,
Err(e) => {
// Instead of using `Log::error`, we'll use `log::error!` for show.
log::error!("Log file creation failed, reason: {}", e);
// This compiles.
std::process::exit(1)
}
};
logfile
}
fn main() {
new_create_logfile();
}
Normally, you need to make sure the return types of all match arms have the same type -- here, you are returning std::fs::File under the Ok branch, so the Err branch can "escape" the requirement by returning ! (pronounced "never") (link).
Since computation never returns from the std::process::exit() and its return type is marked as !, it's passes the type-checking stage.
I have the following rust code and for the life of me I cant workout why I am getting a borrow-checker issue with this value and why does it get moved as part of a while loop.
Code:
#[tokio::main]
async fn main() -> Fallible<()> {
let config = Config::new().expect("config can't be loaded");
logger::config(&config.log);
let bn = Binance::with_credential(
&config.exchanges.binance_com.api_key,
&config.exchanges.binance_com.api_secret,
);
let mut db = Database::new(config).await;
match bn.user_stream_start()?.await {
Ok(_) => {
let mut ws = BinanceWebsocket::default();
for sub in vec![Subscription::Trade("btcusdt".to_string())] {
ws.subscribe(sub).await?;
}
while let Some(msg) = ws.try_next().await? {
db.write(msg).await?
}
}
Err(e) => error!("Error obtaining stream: {}", e),
};
Ok(())
}
Error:
error[E0382]: use of moved value: `db`
--> x/src/main.rs:35:17
|
24 | let mut db = Database::new(config).await;
| ------ move occurs because `db` has type `Database`, which does not implement the `Copy` trait
...
35 | db.write(msg).await?
| ^^ value moved here, in previous iteration of loop
error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0382`.
Any help much appreciated
To avoid nesting matches I am trying to use the and_then method for Result. The problem arises when I try to convert this
match Connection::open(&db_path) {
Ok(conn) => {
match conn.prepare("SELECT qwe,username_value,wer FROM my_table;") {
Ok(mut stmt) => {
match stmt.query_map([], |row| {Ok(row.get_unwrap::<usize, String>(1).clone())}) {
Ok(usernames) => {
for username in usernames {
if username.is_ok() {
println!("{}", username.expect("Could not read username value"));
}
}
println!("Query done");
},
Err(err) => println!("Error {}", err),
}
},
Err(err) => println!("Error {}", err),
}
},
Err(err) => println!("Error {}", err),
}
into this
match Connection::open(&db_path)
.and_then(move |conn: Connection| conn.prepare("SELECT qwe,username_value,wer FROM my_table;"))
.and_then(|mut stmt: Statement| stmt.query_map([], |row| {Ok(row.get_unwrap::<usize, String>(1).clone())})) {
Ok(usernames) => {
for username in usernames {
if username.is_ok() {
println!("{}", username.expect("Could not read username value"));
}
}
println!("Query done");
},
Err(_) => println!("Error querying db"),
}
The SQL lib is rusqlite.
The first snippet is accepted by the compiler, the second one is not.
The compiler screams at me with the following error message:
error[E0515]: cannot return value referencing function parameter `conn`
--> src\main.rs:134:43
|
134 | .and_then(move |conn: Connection| conn.prepare("SELECT qwe,username_value,wer FROM my_table;"))
| ----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| `conn` is borrowed here
error[E0515]: cannot return value referencing function parameter `stmt`
--> src\main.rs:135:41
|
135 | .and_then(|mut stmt: Statement| stmt.query_map([], |row| {Ok(row.get_unwrap::<usize, String>(1).clone())})) {
| ----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| `stmt` is borrowed here
error: aborting due to 2 previous errors
I tried with move on the three closures but the error message is the same.
Why is the ownership wrong in the second snippet and which is the idiomatic way of writing something like this?
The problem is that conn.prepare returns a statement that refers to conn, but conn is destroyed at the end of the closure so it's no longer here when the statement tries to use it. The idiomatic way to do what you want would be to use the ? operator:
let conn = Connection::open(&db_path)?;
let mut stmt = conn.prepare("SELECT qwe,username_value,wer FROM my_table;")?;
for username in stmt.query_map([], |row| {Ok(row.get_unwrap::<usize, String>(1).clone())})? {
if username.is_ok() {
println!("{}", username.expect("Could not read username value"));
}
}
And let the caller handle the error. If you want to handle the error yourself, you can wrap the above code in a local function or closure (see also this question).
I have a set of futures to be run in parallel and if one fails I would like to get the error to return to the caller.
Here is what I have been testing so far:
use futures::prelude::*;
use futures::stream::futures_unordered::FuturesUnordered;
use futures::{future, Future};
fn main() {
let tasks: FuturesUnordered<_> = (1..10).map(|_| async_func(false)).collect();
let mut runtime = tokio::runtime::Runtime::new().expect("Unable to start runtime");
let res = runtime.block_on(tasks.into_future());
if let Err(_) = res {
println!("err");
}
}
fn async_func(success: bool) -> impl Future<Item = (), Error = String> {
if success {
future::ok(())
} else {
future::err("Error".to_string())
}
}
How can I get the error from any failed futures? Even better would be to stop running any pending futures if a single future fails.
Your code is already returning and handling the error. If you attempted to use the error, the compiler will quickly direct you to the solution:
if let Err(e) = res {
println!("err: {}", e);
}
error[E0277]: `(std::string::String, futures::stream::futures_unordered::FuturesUnordered<impl futures::future::Future>)` doesn't implement `std::fmt::Display`
--> src/main.rs:12:29
|
12 | println!("err: {}", e);
| ^ `(std::string::String, futures::stream::futures_unordered::FuturesUnordered<impl futures::future::Future>)` cannot be formatted with the default formatter
|
= help: the trait `std::fmt::Display` is not implemented for `(std::string::String, futures::stream::futures_unordered::FuturesUnordered<impl futures::future::Future>)`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
= note: required by `std::fmt::Display::fmt`
The Err value is a tuple of your error and the original stream to continue pulling after you have dealt with the error. This is what Stream::into_future / StreamFuture does.
Access the first value in the tuple to get to the error:
if let Err((e, _)) = res {
println!("err: {}", e);
}
If you want to see all of the values, you could keep polling the stream over and over (but don't do this because it's probably inefficient):
let mut f = tasks.into_future();
loop {
match runtime.block_on(f) {
Ok((None, _)) => {
println!("Stream complete");
break;
}
Ok((Some(v), next)) => {
println!("Success: {:?}", v);
f = next.into_future();
}
Err((e, next)) => {
println!("Error: {:?}", e);
f = next.into_future();
}
}
}
I'm making a Discord chat bot using discord-rs, starting from this example. Everything was working and compiling fine until I tried to modify a value that is declared before a loop.
I'm trying to change prefix to the second word that is entered in a command:
extern crate discord;
use discord::Discord;
use discord::model::Event;
use std::env;
fn main() {
let discord = Discord::from_bot_token(&env::var("DISCORD_TOKEN").expect("Expected token"))
.expect("login failed");
let (mut connection, _) = discord.connect().expect("connect failed");
println!("Ready.");
let mut prefix = "!";
loop {
match connection.recv_event() {
Ok(Event::MessageCreate(message)) => {
if message.content.starts_with(prefix) {
let msg: Vec<&str> = message.content[prefix.len()..].split(" ").collect();
// message.content gets split into separate words and is checked for the command
match msg[0] {
"ag3nprefix" => {
prefix = msg[1];
// ^ here is the line that makes it not compile
let text = format!("AG3N's command prefix changed to: {}", prefix);
let _ = discord.send_message(message.channel_id, &text, "", false);
}
&_ => {}
}
}
}
Ok(_) => {}
Err(discord::Error::Closed(code, body)) => {
println!("Gateway closed on us with code {:?}: {}", code, body);
break;
}
Err(err) => println!("Receive error: {:?}", err),
}
}
}
I tried doing it various ways, but nothing would work. Here's the error from the compiler:
error[E0597]: `message.content` does not live long enough
--> src/main.rs:38:9
|
19 | let msg: Vec<&str> = message.content[prefix.len()..].split(" ").collect();
| --------------- borrow occurs here
...
38 | }
| ^ `message.content` dropped here while still borrowed
39 | }
40 | }
| - borrowed value needs to live until here
A smaller example
Here's a MCVE of the problem:
fn main() {
let mut prefix = "!";
let mut i = 0;
loop {
let event = String::from("hello");
match i {
0 => prefix = &event,
_ => println!("{}", prefix),
}
i += 1;
}
}
Rust 2015
error[E0597]: `event` does not live long enough
--> src/main.rs:9:28
|
9 | 0 => prefix = &event,
| ^^^^^ borrowed value does not live long enough
...
14 | }
| - `event` dropped here while still borrowed
15 | }
| - borrowed value needs to live until here
Rust 2018
error[E0597]: `event` does not live long enough
--> src/main.rs:9:27
|
9 | 0 => prefix = &event,
| ^^^^^^ borrowed value does not live long enough
10 | _ => println!("{}", prefix),
| ------ borrow used here, in later iteration of loop
...
14 | }
| - `event` dropped here while still borrowed
The core issue is that event is dropped at the end of each iteration. However, the code attempts to use prefix, a reference to event, in a subsequent iteration. If that were allowed to happen, you'd be accessing invalid memory, causing undefined behavior. Rust disallows this from happening.
You need to change the code so that event (or the part of it you need) lives longer than any one loop iteration.
Applied to the original code
The golden rule for borrowing problems is to identify who owns a variable. The compiler error messages help you here:
`message.content` does not live long enough
Ok, so we need to look at message.content or just message. Who owns that? We've matched a enum and transferred ownership to a local variable called message, so the variable message is the owner:
Ok(Event::MessageCreate(message)) => {
The compiler error message agrees, as this error points to the block where message is in scope (actually the match braces for technical reasons):
^ `message.content` dropped here while still borrowed
You are trying to take a reference to that string and store the reference somewhere that needs to live longer than a single loop iteration. The compiler has stopped you from introducing memory unsafety into your program. In other languages, you'd write this code and at some point in the future your program would crash (at best) or leak sensitive information or allow injecting code in (at worst).
Instead, allocate a String inside the loop. Because it has its own allocation, it can live longer than message. You also need to change the type of the original value of prefix and change the call to starts_with:
let mut prefix = "!".to_string();
loop {
match connection.recv_event() {
Ok(Event::MessageCreate(message)) => {
if message.content.starts_with(&prefix) {
let msg: Vec<_> = message.content[prefix.len()..].split(" ").collect();
// message.content gets split into separate words and is checked for the command
match msg[0] {
"ag3nprefix" => {
prefix = msg[1].to_string();
// ^ here is the line that makes it not compile
let text = format!("AG3N's command prefix changed to: {}", prefix);
let _ = discord.send_message(message.channel_id, &text, "", false);
}
&_ => {}
}
}
}
Ok(_) => {}
Err(discord::Error::Closed(code, body)) => {
println!("Gateway closed on us with code {:?}: {}", code, body);
break;
}
Err(err) => println!("Receive error: {:?}", err),
}
}
let _ = discord.send_message(message.channel_id, &text, "", false);
DO NOT IGNORE ERRORS. If you don't want to handle it, just add .expect("I didn't handle this error").