我设法想出了三个场景,在我看来表面上是相同的,但行为不同,如果有人能向我澄清原因,我将不胜感激……

第一个场景不符合我的实际预期:

fn main() {
    let data = get_data();
    println!("{}", data);
}

fn get_data() -> &'static str {
    let x: String = String::from("hello");
    return x.as_str(); // always fails with ownership issue
}

不出所料失败:returns a reference to data owned by the current function

然而,考虑到上面的预期,接下来的两个问题让我感到困惑:

这是成功的:

fn get_data() -> &'static str { // requires `'static` lifetime
    let x = std::path::Path::new("thing");
    match x.to_str() {
        None => "",
        Some(s) => s,
    }
}

我本以为s是函数所拥有的,所以不能返回,但在本例中,添加&'static str作为返回类型(否则编译器会不高兴)允许该操作.

更令人费解的是,以下代码可以工作(编译器很高兴),not是否需要'static个生命周期:

use std::path::Path;

pub fn parent_of(caller_file: &str) -> &str { // `'static` not required ??
    let caller_file_p: &Path = Path::new(caller_file);

    match caller_file_p.parent() {
        None => if caller_file.starts_with("/") { "/" } else { "." },
        Some(p) => match p.to_str() {
            None => {
                eprintln!("Bad UTF-8 sequence specified : '{}'", caller_file);
                std::process::exit(100);
            },
            Some(s) => s,
        }
    }
}

我相信每个场景的细微差别都有一些有条不紊的解释,但我搞不懂.非常感谢您的澄清.

推荐答案

在第二种情况下,您通过Path::new()&'static str(字符串文字)转换为&Path.Path::new()保留引用的生存期(因为Path不是拥有的类型,而是borrow 的类型,基本上是对其他人拥有的字节的包装,无论是PathBufString,还是在字符串文字情况下的二进制本身).所以你得&'static PathBuf分.通过Path::to_str()将其转换回&str,您将得到&'static str.

在第三种情况下,您有字符串文字(&'static str)和生存期为caller_file&Path.如果我们注解生命周期:

pub fn parent_of<'caller_file>(caller_file: &'caller_file str) -> &'caller_file str {
    // `'static` not required ??
    let caller_file_p: &'caller_file Path = Path::new(caller_file);

    match caller_file_p.parent() {
        None => {
            if caller_file.starts_with("/") {
                "/" // `&'static str`
            } else {
                "." // `&'static str`
            }
        }
        Some(p) => match p.to_str() {
            None => {
                eprintln!("Bad UTF-8 sequence specified : '{}'", caller_file);
                std::process::exit(100);
            }
            Some(s) => s, // `s` is `&'caller_file str`
        },
    }
}

通过lifetime elision条规则,假定返回类型的生存期为'caller_file.字符串"/""."&'static str,由于'static大于(或等于)任何生存期,因此可以将它们缩小到&'caller_file str.caller_file_p&'caller_file Path,它的to_str()&'caller_file str,所以这是预期的.

Rust相关问答推荐

有没有方法处理rust中嵌套的ok_or()?

移植带有可变borrow 的C代码-卸载期间错误(nappgui示例)

包含嵌套 struct 的CSV

如何对字符串引用的引用向量进行排序,而不是对最外层的引用进行排序?

如果A == B,则将Rc A下推到Rc B

我如何在Rust中使用传递依赖中的特征?

当rust中不存在文件或目录时,std::FS::File::Create().unwire()会抛出错误

这个规则关于或模式到底是什么意思?如果表达片段的类型与p_i|q_i...&q;不一致,就会形成

如何高效地将 struct 向量中的字段收集到单独的数组中

为什么这个变量不需要是可变的?

Rust移动/复制涉及实际复制时进行检测

Rust 中什么时候可以返回函数生成的字符串切片&str?

为什么 Rust 创建的 f32 小于 f32::MIN_POSITIVE?

Rust 如何将链表推到前面?

Rust 中的生命周期:borrow 的 mut 数据

在 Rust 中实现资源消耗的安全包装器

在构建器模式中捕获 &str 时如何使用生命周期?

使用 rust 在 google cloud run (docker) 中访问环境变量的适当方法

我可以在不调用 .clone() 的情况下在类型转换期间重用 struct 字段吗?

在同一向量 Rust 中用另一个字符串扩展一个字符串