简体   繁体   中英

Checking if folder exists in directory

I want to know if the folder foo exists in my current directory, so I wrote a function to do so:

use std::env;
use std::fs;
use std::io;

fn does_folder_foo_exist_in_current_directory() -> Result<bool, io::Error> {
    let cur_path_buf = env::current_dir()?;
    let cur_dir = cur_path_buf.as_path();
    Ok(fs::read_dir(cur_dir)?.find(|ref x| {
        let x = x.unwrap();
        x.file_type().unwrap().is_dir() && x.file_name().to_str().unwrap() == "foo"
    }).is_some())
}

However, the compiler says that I cannot move out of borrowed content here: let x = x.unwrap(); .

Why is this moving out of borrowed content since I ref x ?

ref in patterns is used to construct a reference. If the pattern x would have type T , then the pattern ref x will have type &T instead. However, it's not valid to move out of a reference, so you definitely don't want to construct a reference! ( unwrap takes self by value, which is why the code is trying to do a move in the first place.)

Here, the type of the parameter on the closure is a reference, because that's what Iterator::find wants to pass as an argument. If you want to deconstruct a reference, you want to use & instead. However, if you write the pattern &x here, you'll still get the error cannot move out of borrowed content , but this time directly on &x .

What can we do instead? DirEntry doesn't implement Clone , therefore we can't clone x (which is an &std::io::Result<DirEntry> ). Instead, we could turn the &Result<DirEntry> into a Result<&DirEntry> . There's a method in the standard library to do just that: as_ref .

fn does_folder_foo_exist_in_current_directory() -> Result<bool, io::Error> {
    let cur_path_buf = env::current_dir()?;
    let cur_dir = cur_path_buf.as_path();
    Ok(fs::read_dir(cur_dir)?.find(|x| {
        let x = x.as_ref().unwrap();
        x.file_type().unwrap().is_dir() && x.file_name().to_str().unwrap() == "foo"
    }).is_some())
}

By the way, instead of doing find(...).is_some() , you can use any(...) , which is shorter and perhaps slightly more efficient. any also passes ownership of each iterated value to the closure, so we don't actually need to use as_ref with it!

fn does_folder_foo_exist_in_current_directory() -> Result<bool, io::Error> {
    let cur_path_buf = env::current_dir()?;
    let cur_dir = cur_path_buf.as_path();
    Ok(fs::read_dir(cur_dir)?.any(|x| {
        let x = x.unwrap();
        x.file_type().unwrap().is_dir() && x.file_name().to_str().unwrap() == "foo"
    }))
}

There's no reason to iterate over all the entries in a directory to check if a single item exists. Just check for the specific item:

use std::{env, fs, io};

fn does_folder_foo_exist_in_current_directory() -> io::Result<bool> {
    let mut path = env::current_dir()?;
    path.push("foo");
    let metadata = fs::metadata(path)?;
    Ok(metadata.is_dir())
}

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM