I am new to rust and trying to figure out what I am doing wrong here. From the docs.rs page on walkdir:
The following code recursively iterates over the directory given and prints the path for each entry:
use walkdir::WalkDir;
for entry in WalkDir::new("foo") {
println!("{}", entry?.path().display());
}
However when I try to run this as a simple program:
use walkdir::WalkDir;
fn main() {
for entry in WalkDir::new("~/Documents/ExampleDir/") {
println!("{}", entry?.path().display());
}
}
I get a compilation error:
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`)
--> src/main.rs:4:24
|
2 | / fn main() {
3 | | for entry in WalkDir::new("foo") {
4 | | println!("{}", entry?.path().display());
| | ^^^^^^ cannot use the `?` operator in a function that returns `()`
5 | | }
6 | | }
| |_- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `Try` is not implemented for `()`
= note: required by `from_error`
If I remove the ? operator then I get a different compilation error:
error[E0599]: no method named `path` found for enum `std::result::Result<walkdir::DirEntry, walkdir::Error>` in the current scope
--> src/main.rs:4:30
|
4 | println!("{}", entry.path().display());
| ^^^^ method not found in `std::result::Result<walkdir::DirEntry, walkdir::Error>`
What am I doing wrong here? Is this an issue in my code or in the documentation?
The ? is shorthand for a match statement. See The question mark operator.
The question mark operator (?) unwraps valid values or returns erroneous values, propagating them to the calling function. It is a unary postfix operator that can only be applied to the types Result<T, E> and Option.
The (main) function requires a return value of type Result:
use std::error::Error;
use walkdir::WalkDir;
fn main() -> Result<(), Box<dyn Error>> {
for entry in WalkDir::new("~/Documents/ExampleDir/") {
println!("{}", entry?.path().display());
}
Ok(())
}
Related
I have a closure that looks like this:
pub fn getBytes(bytes: Vec<String>) -> Result(String, InputError) {
bytes.iter().for_each(|byte| {
let mut fixed_byte = String::new();
if byte.contains("0x") {
fixed_byte = dict::add_push(byte);
if fixed_byte.trim() == String::from("Wrong length") {
return Err(InputError::WrongHexLength(byte.to_string())); // Problem is here
}
}
bytecode.push_str(&fixed_byte);
});
Ok(bytecode)
}
And I want to return a custom error, but since it's inside a closure I get an error like this:
mismatched types
--> src/lib.rs:110:24
|
110 | return Err(InputError::WrongHexLength(byte.to_string()))
;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
expected `()`, found enum `Result`
|
= note: expected unit type `()`
found enum `Result<_, InputError>`
How can I terminate what the closure does and just return the error?
Thanks!
Use try_for_each. As documentation says:
An iterator method that applies a fallible function to each item in the iterator, stopping at the first error and returning that error.
Alternatively use for loop and more imperative approach instead of functional for_each.
mystring.rs
pub fn return_string() {
return "Some String"
}
then in main, I want to print this string
mod mystring;
const test = config::return_string();
println!("{}", test);
the error I get is
println!("{}", test);
| ^^^^ `()` cannot be formatted with the default formatted
I assume that your minimal reproducible example is:
pub fn return_string() {
return "Some String"
}
fn main() {
const test = return_string();
println!("{}", test);
}
error: missing type for `const` item
--> src/main.rs:6:11
|
6 | const test = return_string();
| ^^^^ help: provide a type for the constant: `test: ()`
error[E0308]: mismatched types
--> src/main.rs:2:12
|
1 | pub fn return_string() {
| - help: try adding a return type: `-> &'static str`
2 | return "Some String"
| ^^^^^^^^^^^^^ expected `()`, found `&str`
error[E0277]: `()` doesn't implement `std::fmt::Display`
--> src/main.rs:7:20
|
7 | println!("{}", test);
| ^^^^ `()` cannot be formatted with the default formatter
|
= help: the trait `std::fmt::Display` is not implemented for `()`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
= note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
Solution
There are two errors in your code:
don't use const inside of functions. Use let. let is an immutable value. let mut would be mutable. const is only used for immutable globals.
you are missing the return type for your return_string() function
I'll assume here that the return type is &str, but it might as well have to be String. For more info search for &str vs String.
Third, as a minor annotation, avoid return as much as possible, if not required. The last line of a function is automatically the return type if you don't finish it with ;.
pub fn return_string() -> &'static str {
"Some String"
}
fn main() {
let test = return_string();
println!("{}", test);
}
Some String
Explanation of the error message
The error message says that () is not printable.
() is the empty type, analogous to void in C++. As you don't annotate the return type of return_string(), Rust assumes it's (). And () cannot be printed directly, at least not with the Display formatter.
You could print it with the Debug formatter, though:
pub fn return_void() {}
fn main() {
let test = return_void();
println!("{:?}", test);
}
()
Note that contrary to C++, () is actually a storable type, even if it is of size 0 with no data in it. That makes things a lot easier for generics. C++ templates that need to be able to deal with void return values were a major pain factor for me in the past, as they always required a special case.
struct DummyRtspClient<'a> {
on_produce: &'a dyn Fn(EncodedPacket)
}
impl ... for DummyRtspClient {
fn set_on_produce(&self, f: &'a dyn Fn(EncodedPacket)){
self.on_produce = f;
}
}
Then how can I use on_produce?
I tried
let encoded_packet = EncodedPacket{
data: Vec::new(),
};
self.on_produce(encoded_packet);
but it says that on_produce is not a member function, but a field.
I tried self.on_produce.call(encoded_packet) but I also get errors.
Your error message should say something like this:
error[E0599]: no method named `on_produce` found for reference `&DummyRtspClient<'a>` in the current scope
--> src/lib.rs:14:18
|
14 | self.on_produce(encoded_packet);
| ^^^^^^^^^^ field, not a method
|
help: to call the function stored in `on_produce`, surround the field access with parentheses
|
14 | (self.on_produce)(encoded_packet);
| ^ ^
In particular, the second part tells exactly you how to solve this: wrap self.on_produce in a set of parentheses to disambiguate it from attempting to call a member function.
I'm trying to match on the datatype of a generic field of a struct and react accordingly. My general idea was like this (code doesn't compile):
struct Foo<T> {
bar: T,
}
fn main() {
let x = Foo::<String> {
bar: "world".to_string(),
};
match x.bar {
String => println!("It's a string!"),
u32 => println!("It's a u32!"),
_ => println!("Something else"),
};
println!("end of program!");
}
The error message from the compiler:
warning: unreachable pattern
--> src/main.rs:12:9
|
11 | String => println!("It's a string!"),
| ------ matches any value
12 | u32 => println!("It's a u32!"),
| ^^^ unreachable pattern
|
= note: `#[warn(unreachable_patterns)]` on by default
warning: unreachable pattern
--> src/main.rs:13:9
|
11 | String => println!("It's a string!"),
| ------ matches any value
12 | u32 => println!("It's a u32!"),
13 | _ => println!("Something else"),
| ^ unreachable pattern
warning: unused variable: `String`
--> src/main.rs:11:9
|
11 | String => println!("It's a string!"),
| ^^^^^^ help: consider prefixing with an underscore: `_String`
|
= note: `#[warn(unused_variables)]` on by default
warning: unused variable: `u32`
--> src/main.rs:12:9
|
12 | u32 => println!("It's a u32!"),
| ^^^ help: consider prefixing with an underscore: `_u32`
warning: variable `String` should have a snake case name
--> src/main.rs:11:9
|
11 | String => println!("It's a string!"),
| ^^^^^^ help: convert the identifier to snake case: `string`
|
= note: `#[warn(non_snake_case)]` on by default
What I wanted was for x to match the first one. I'm actually not sure what I want to do can be done, but what would achieve the desired effect?
Idiomatic Solution
Create a trait which constrains the parameter T in Foo, implement any specific behavior as an associated function of this trait.
Example:
trait PrintMe {
fn print_me(&self);
}
impl PrintMe for String {
fn print_me(&self) { println!("I am a string"); }
}
struct Foo<T: PrintMe> {
bar: T
}
fn main() {
// ...
x.bar.print_me();
}
This is principled generic programming, where you declare exactly the difference of behavior of the possible generic parameters, so that there is no surprise.
See also:
Why is this match pattern unreachable when using non-literal patterns?
Exact Solution
Rust can indeed query types: each type has a unique TypeId associated, and you can match on TypeId with a series of if checks. It's clunky.
fn print_me<T>(x: &Foo<T>) {
if TypeId::of::<T>() == TypeId::of::<String>() {
println!("I am a string");
} else // ...
}
But please... don't do that :)
A more general look at matching over types
Basically, you hardly can match on the type, instead you have to use rust's traits.
Here is a helpful introduction for Rust's traits:
https://doc.rust-lang.org/rust-by-example/trait.html
I will explain simply how to match over type so it's okay if you don't know how to use traits.
Here is how to more generally change behavior depending on the type:
Define a trait that is going to do something depending on the type.
Add a function that takes in what you need to do something with it.
It will take the variable with a type that varies as self. Don't add a body to that function, just follow the definition with a semicolon ;.
trait DoSomething {
fn someFunction(&self);
}
Implement the trait for all the types you wanted to match for: String and u32.
This is the part where you can code different behavior for each type.
impl DoSomething for String {
fn someFunction(&self) {
println!("It is a string!")
}
}
impl DoSomething for u32 {
fn someFunction(&self) {
println!("It is a u32!")
}
}
Instead of matching on an element, call the method in the trait on it.
struct Foo<T> {
bar: T,
}
fn main() {
let x = Foo::<String> {
bar: "world".to_string(),
};
// the call of the method someFunction will differentiate the type of x.bar
x.bar.someFunction();
}
TLDR: in Rust, to match over type, we create a trait, implement a function for each type and call it on the element to match.
The choice seems to be between std::fs::PathExt and std::fs::metadata, but the latter is suggested for the time being as it is more stable. Below is the code I have been working with as it is based off the docs:
use std::fs;
pub fn path_exists(path: &str) -> bool {
let metadata = try!(fs::metadata(path));
assert!(metadata.is_file());
}
However, for some odd reason let metadata = try!(fs::metadata(path)) still requires the function to return a Result<T,E> even though I simply want to return a boolean as shown from assert!(metadata.is_file()).
Even though there will probably be a lot of changes to this soon enough, how would I bypass the try!() issue?
Below is the relevant compiler error:
error[E0308]: mismatched types
--> src/main.rs:4:20
|
4 | let metadata = try!(fs::metadata(path));
| ^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found enum `std::result::Result`
|
= note: expected type `bool`
found type `std::result::Result<_, _>`
= note: this error originates in a macro outside of the current crate
error[E0308]: mismatched types
--> src/main.rs:3:40
|
3 | pub fn path_exists(path: &str) -> bool {
| ________________________________________^
4 | | let metadata = try!(fs::metadata(path));
5 | | assert!(metadata.is_file());
6 | | }
| |_^ expected (), found bool
|
= note: expected type `()`
found type `bool`
Note that many times you want to do something with the file, like read it. In those cases, it makes more sense to just try to open it and deal with the Result. This eliminates a race condition between "check to see if file exists" and "open file if it exists". If all you really care about is if it exists...
Rust 1.5+
Path::exists... exists:
use std::path::Path;
fn main() {
println!("{}", Path::new("/etc/hosts").exists());
}
As mental points out, Path::exists simply calls fs::metadata for you:
pub fn exists(&self) -> bool {
fs::metadata(self).is_ok()
}
Rust 1.0+
You can check if the fs::metadata method succeeds:
use std::fs;
pub fn path_exists(path: &str) -> bool {
fs::metadata(path).is_ok()
}
fn main() {
println!("{}", path_exists("/etc/hosts"));
}
You can use std::path::Path::is_file:
use std::path::Path;
fn main() {
let b = Path::new("file.txt").is_file();
println!("{}", b);
}
https://doc.rust-lang.org/std/path/struct.Path.html#method.is_file