I'm learning Rust and failed on the first steps already... I have the next function:
use std::env;
use std::path::Path;
fn get_path() -> Path {
let args: Vec<String> = env::args().collect();
assert!(!args.is_empty(), "Target path is required!");
let path = Path::new(&args[0]);
assert!(path.exists(), "Target path doesn't exist!");
assert!(path.is_dir(), "Target path is not a directory!");
return path;
}
It's very simple function but path
is a reference and I can't get how can I return Path
object from function by value? Or how to return a reference that will be alive in outer function context?
PS I looked for similar question but I didn't get it, unfortunately.
Strictly speaking, Path
is not a reference, it is rather an unsized type which can only exist behind a reference, and indeed Path::new
returns &Path
not Path
. Which is therefore incompatible with the -> Path
you've annotated your function with.
These are in fact the two things the compile error tells you, and you really want to give people compilation errors (or reproduction cases) when posting Rust code as the errors are extremely informative once you've gotten used to them:
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> src/lib.rs:4:18
|
4 | fn get_path() -> Path {
| ^^^^ borrow the `Path` instead
|
says that you're returning an unsized type which is not allowed), and
error[E0308]: mismatched types
--> src/lib.rs:10:12
|
4 | fn get_path() -> Path {
| ---- expected `std::path::Path` because of return type
...
10 | return path;
| ^^^^ expected struct `std::path::Path`, found `&std::path::Path`
explains that the type you want to return doesn't match the type of the value you're returning.
Anyway as the official documentation for Path
notes , the owned / structure version of Path
is PathBuf
, so you should return that, and convert your Path
into a PathBuf
, or really just create a PathBuf
in the first place, eg
use std::env;
use std::path::PathBuf;
fn get_path() -> PathBuf {
let args: Vec<String> = env::args().collect();
assert!(!args.is_empty(), "Target path is required!");
let path = PathBuf::from(&args[0]);
assert!(path.exists(), "Target path doesn't exist!");
assert!(path.is_dir(), "Target path is not a directory!");
path
}
Incidentally,
Path::new(&args[0]);
is probably not what you expect or want: as the documentation for std::env::args
notes:
The first element is traditionally the path of the executable
and this is not an area where Rust has seen fit to diverge from the underlying system.
You likely want args[1]
instead, or to use a higher-level args-parsing API.
And an other aside related to Sven Marnach's comment to your question: calling path.exists
then path.is_dir
requires fetching the metadata twice (I don't think Rust caches this information). The efficienty aspect is probably not primordial here but you may still want to explicitly use Path::metadata
, followed by asking that if is_dir
( Path::metadata
will return an Err
if the path is not to a valid on-disk thing).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.