When can string slice `&str` produced by a function be returned in Rust?

tk-*_*dle 2 rust

I've managed to cook up three scenarios which to me seem on the surface to be the same, but behave differently, and I would appreciate if someone could clarify to me why...

The first scenario fails to complile, as I would actually expect :

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
}
Run Code Online (Sandbox Code Playgroud)

Fails as expected: returns a reference to data owned by the current function

However the next two confound me given the above expectation:

This succeeds:

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

I would have thought s was owned in the function so couldn't be returned, but in this case, adding &'static str as return type (compiler is unhappy otherwise) allows the operation.

More puzzlingly still, the following works (compiler is happy), and does not require the 'static lifetime:

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,
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

I'm sure there's some methodical explanation as to the nuances of each scenario, but it eludes me. Clarifications most appreciated.

Cha*_*man 7

在第二种情况下,您将 a &'static str(字符串文字)转换为&Pathvia Path::new()Path::new()保留引用的生命周期(因为Path不是自有类型,而是借用类型,基本上是其他人拥有的字节的一些包装器,无论是 a PathBuf、 a String,还是字符串文字情况下的二进制本身)。所以你得到了&'static PathBuf。将其转换回&strviaPath::to_str()你会得到&'static str.

在第三种情况下,您有字符串文字 ( &'static strs) 且&Path生命周期为caller_file。如果我们注释生命周期:

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`
        },
    }
}
Run Code Online (Sandbox Code Playgroud)

'caller_file假定返回类型的生命周期是通过生命周期省略规则实现的。字符串文字"/""."&'static str,并且由于'static大于(或等于)任何生命周期,因此它们可以缩小为&'caller_file strcaller_file_pis &'caller_file Path,它的to_str()is &'caller_file str,所以这按预期工作。