Есть ли способ избежать клонирования при преобразовании PathBuf в строку?

Мне нужно просто (и опасно - обработка ошибок опущена для краткости) получить текущее имя исполняемого файла. Я сделал это работает, но моя функция преобразует &str в String только позвонить as_str() позже для сопоставления с образцом.

fn binary_name() -> String {
    std::env::current_exe().unwrap().file_name().unwrap().to_str().unwrap().to_string()
}

Как я понимаю, std::env::current_exe() дает мне право собственности на PathBuf который я мог бы передать, вернув его. В настоящее время я одалживаю его, чтобы преобразовать в &str, Оттуда единственный способ вернуть строку - это клонировать ее до PathBuf упал

Есть ли способ избежать этого &OsStr -> &str -> String -> &str цикл?

1 ответ

Решение

Есть ли способ избежать клонирования при конвертации PathBuf к String?

Абсолютно. Однако это не то, что вы делаете. Вы принимаете участие в PathBuf с помощью file_name и преобразовать это. Вы не можете стать владельцем части строки.

Если вы не брали подмножество, то конвертирование целого PathBuf может быть сделано путем преобразования в OsString а затем к String, Здесь я игнорирую конкретные ошибки и просто возвращаю успех или неудачу:

use std::path::PathBuf;

fn exe_name() -> Option<String> {
    std::env::current_exe()
        .ok()
        .map(PathBuf::into_os_string)
        .and_then(|exe| exe.into_string().ok())
}

Есть ли способ избежать этого &OsStr -> &str -> String -> &str цикл?

Нет, потому что вы создаете String (или же OsString или же PathBufв зависимости от варианта кода) внутри вашего метода. Проверьте возврат локальной строки в качестве среза (&str), почему вы не можете вернуть ссылку на выделенный стеком элемент (включая строку).

Как указано в этом разделе "Вопросы и ответы", если вы хотите иметь ссылки, то вещь, владеющая данными, должна пережить ссылки:

use std::env;
use std::path::Path;
use std::ffi::OsStr;

fn binary_name(path: &Path) -> Option<&str> {
    path.file_name().and_then(OsStr::to_str)
}

fn main() {
    let exe = env::current_exe().ok();
    match exe.as_ref().and_then(|e| binary_name(e)) {
        Some("cat") => println!("Called as cat"),
        Some("dog") => println!("Called as dog"),
        Some(other) => println!("Why did you call me {}?", other),
        None => println!("Not able to figure out what I was called as"),
    }
}

Ваш исходный код может быть написан так, чтобы достаточно легко избежать ошибок

fn binary_name() -> Option<String> {
    let exe = std::env::current_exe();
    exe.ok()
        .as_ref()
        .and_then(|p| p.file_name())
        .and_then(|s| s.to_str())
        .map(String::from)
}
Другие вопросы по тегам