Rust 函数的返回值不能引用局部变量或临时变量

Return value from Rust function cannot reference local or temporary variable

提问人:Jacob Runge 提问时间:11/2/2023 最后编辑:Jacob Runge 更新时间:11/2/2023 访问量:83

问:

上下文

无法使此功能正常工作。我相信我理解错误试图告诉我什么,但我不明白我是如何犯错的/如何解决它们。

该函数是一个递归函数,它查看目录及其子目录并累积路径的向量和 Axum MethodRouter(我认为这与我面临的实际问题没有任何关系)。

错误

编译器错误指出“无法返回引用局部变量的值”。path

如果我替换为 ,错误就变成了“无法返回引用临时值的值”。path.to_str()path.clone().to_str()

法典

fn assign_handlers(dir: Option<&str>) -> Vec<(&str, MethodRouter)> {
    //Check root dir validity
    let dir = match dir {
        Some(s) => s,
        None => return vec![],
    };

    //Look for routes in dir
    let dir_path = fs::read_dir(dir).expect(&format!("Unable to access directory '{}'", &dir));
    let mut routes = Vec::new();
    for entry in dir_path {
        match entry {
            Ok(entry) => {
                let path = entry.path();
                if path.is_dir() {
                    //Recurse into subdirectories
                    let subroutes = assign_handlers(path.to_str());
                    for route in subroutes {
                        routes.push(route)
                    }
                } else if path.is_file() {
                    // Cut for brevity (and because I don't know what goes here yet)
                }
            },
            Err(_) => {},
        }
    }

    routes
}
Rust 借用检查器

评论

1赞 Marco Bonelli 11/2/2023
除了借用检查错误...这个函数将如何返回任何东西?它总是会返回一个空的 vec。它只是实际函数的不完整简化版本吗?
0赞 Jacob Runge 11/2/2023
正确。。。不完整和简化。我会对空的 vec 感到满意。
1赞 Marco Bonelli 11/2/2023
啊好吧,只是检查一下。在任何情况下,您都可以简单地将返回类型更改为执行复制,以便借阅检查器满意。Vec<String, MethodRouter>
0赞 Jacob Runge 11/2/2023
Marco -- 我已经编辑了代码,使遗漏变得清晰。谢谢!
1赞 Chayim Friedman 11/2/2023
吹毛求疵:调用效率更高,因为这样可以节省系统调用(通常)。entry.file_type().is_dir()entry.path().is_dir()

答:

2赞 Yoric 11/2/2023 #1

Rust 是正确的。让我们解码 :表示它是引用,表示它是字符串的内容。在垃圾回收语言中,引用使对象保持活动状态,这很方便,但 Rust 做出了不同的选择,它通常更快、内存效率更高,并且可以用来查找编译器在其他语言中会让传递的许多错误:引用不会让对象保持活动状态。&str&str

编译器是这样告诉你的:根据定义,临时值是一旦你离开块就不再存在的值。由于您在函数中指定的返回类型包含 ,因此编译器信任您,并假定其中包含临时值,并且您正在尝试返回它们。由于无法返回临时值,因此会出现错误。&strsubroutes

所以,你应该做的是返回一些保证活着的东西。例如,这可以是 。除了,在这种情况下,你已经有一些活的东西:a - 相当于一个 ,除了它使用你的文件系统的编码,正如你的操作系统所要求的那样(许多语言混淆了 a 和 a - 这使得大多数用这些语言编写的应用程序在日本、韩国或中国无法使用,例如)。StringPathBufStringPathBufString

通过这些更改,您将获得:

fn assign_handlers(dir: Option<&Path>) -> Vec<(PathBuf, MethodRouter)> {
    //Check root dir validity
    let dir = match dir {
        Some(s) => s,
        None => return vec![],
    };

    //Look for routes in dir
    let dir_path = fs::read_dir(dir).expect(&format!("Unable to access directory '{:?}'", &dir));
    let mut routes = Vec::new();
    for entry in dir_path {
        match entry {
            Ok(entry) => {
                let path = entry.path();
                if path.is_dir() {
                    //Recurse into subdirectories
                    let subroutes = assign_handlers(Some(&path));
                    for route in subroutes {
                        routes.push(route)
                    }
                } else if path.is_file() {

                }
            },
            Err(_) => {},
        }
    }

    routes
}

另外,我不确定你为什么要通过.我建议只传递一个.这将稍微简化代码。Option<&PathBuf>&PathBuf

评论

2赞 Marco Bonelli 11/2/2023
“根据定义,临时值是一旦你离开区块就不再存在的值。”- OP 虽然没有临时返回,也没有在返回的 中引用 传递 ,所以借用检查器给出的错误似乎有点奇怪。pathvec
0赞 Yoric 11/2/2023
好吧,他们声称他们通过指定函数的返回来这样做。但你是对的,我的回答需要澄清。&str
1赞 Jacob Runge 11/2/2023
Yoric -- 非常有帮助 -- 这有助于简化我对参考文献如何工作的心理模型。有关的信息也非常有趣和有用。Marco -- 这也是我陷入困境的地方,我不明白它是如何被束缚的。我认为这是因为最终进入了递归函数调用,但我对为什么这很重要的理解仍然有点不稳定。PathBufvecpathpathdir