2017-01-23 8 views
2

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

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 цикл?

ответ

3

Есть ли способ избежать клонирования при преобразовании 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, в зависимости от того имеет место право собственности в зависимости от варианта кода) внутри вашего метода. Проверьте Return local String as a slice (&str) за то, почему вы не можете вернуть ссылку на элемент, выделенный стекю (включая строку).

Как указано в том, что Q & А, если вы хотите иметь ссылки, дело владеющие данными должен пережить ссылки:

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) 
} 
+0

Уход. Я думал, что не будет никакого способа, не перемещая владения за пределы функции. Просто мои сильные стороны. – mgoszcz2

+0

@ mgoszcz2 Я не уверен, что следую за вами - в первом и третьем примерах выделяются новые данные, а во втором примере свойство * * находится вне функции. – Shepmaster

+0

Нет, я просто вернул указатель на 'argv [0] + offset' – mgoszcz2