2017-01-23 4 views
2

Je dois simplement (et dangereusement - gestion des erreurs omises par souci de concision) obtenir le nom de l'exécutable actuel. Je l'ai fait travailler, mais ma fonction convertit un &str-String que pour appeler as_str() là-dessus plus tard pour le filtrage.Existe-t-il un moyen d'éviter le clonage lors de la conversion d'un PathBuf en String?

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

Si je comprends bien, std::env::current_exe() me donne la propriété du PathBuf que je pouvais transférer en la retournant. En l'état, je l'emprunte pour le convertir en &str. De là, la seule façon de retourner la chaîne est de la cloner avant que le PathBuf ne soit supprimé.

Est-il possible d'éviter ce cycle &OsStr -> &str -> String -> &str?

Répondre

3

Y at-il un moyen d'éviter le clonage lors de la conversion d'un PathBuf à un String?

Absolument. Cependant, ce n'est pas ce que vous faites. Vous prenez une partie du PathBuf via file_name et convertir cela. Vous ne pouvez pas prendre possession d'une partie d'une chaîne.

Si vous ne preniez pas de sous-ensemble, la conversion d'un PathBuf entier peut être effectuée en convertissant en OsString puis en String. Ici, j'ignore les erreurs spécifiques et juste retour succès ou l'échec:

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()) 
} 

Est-il possible d'éviter ce cycle &OsStr -> &str -> String -> &str?

Non, parce que vous créez le String (ou OsString ou PathBuf, selon détient une participation en fonction de la variante de code) à l'intérieur de votre méthode. Consultez Return local String as a slice (&str) pour savoir pourquoi vous ne pouvez pas renvoyer une référence à un élément alloué par une pile (y compris une chaîne).

Comme indiqué dans ce Q & A, si vous voulez avoir des références, la chose de posséder les données doit survivre les références:

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"), 
    } 
} 

Votre code original peut être écrit pour ne pas tomber en panne sur erreurs assez facilement

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

Neat. Je pensais qu'il n'y aurait aucun moyen sans déplacer la propriété en dehors de la fonction. Juste mes manières de C qui brillent à travers. – mgoszcz2

+0

@ mgoszcz2 Je ne suis pas sûr que je te suis - dans les premier et troisième exemples, de nouvelles données sont alloués, et dans le second exemple, la propriété * est * à l'extérieur de la fonction. Non, ce – Shepmaster

+0

est juste en C Je voudrais juste revenir un pointeur vers 'argv [0] + offset' – mgoszcz2