2016-11-12 50 views
1

在Python中,名爲os.path.join()的函數允許使用操作系統的路徑分隔符將多個字符串連接成一個路徑。在Rust中,只有一個函數join()將字符串或路徑附加到現有路徑。這個問題不能用普通函數來解決,因爲普通函數需要有固定數量的參數。用於連接Rust中路徑的宏

我正在尋找一個接受任意數量的字符串和路徑並返回連接路徑的宏。

回答

1

一旦你讀過宏語法,它並不算太壞。基本上,我們需要至少兩個參數,第一個需要通過Into轉換爲PathBuf。後面的每個參數都是push,它接受任何可以變成對Path的引用的內容。

macro_rules! build_from_paths { 
    ($base:expr, $($segment:expr),+) => {{ 
     let mut base: ::std::path::PathBuf = $base.into(); 
     $(
      base.push($segment); 
     )* 
     base 
    }} 
} 

fn main() { 
    use std::path::{Path, PathBuf}; 
    use std::ffi::OsStr; 

    let a = build_from_paths!("a", "b", "c"); 
    println!("{:?}", a); 

    let b = build_from_paths!(PathBuf::from("z"), OsStr::new("x"), Path::new("y")); 
    println!("{:?}", b); 

} 
2

一個正常的函數,它接受可迭代(例如,切片)可以在許多情況下解決問題:

use std::path::{Path, PathBuf}; 

fn join_all<P, Ps>(parts: Ps) -> PathBuf 
    where Ps: IntoIterator<Item = P>, 
      P: AsRef<Path> 
{ 
    parts.into_iter().fold(PathBuf::new(), |mut acc, p| { 
     acc.push(p); 
     acc 
    }) 
} 

fn main() { 
    let parts = vec!["/usr", "bin", "man"]; 
    println!("{:?}", join_all(&parts)); 
    println!("{:?}", join_all(&["/etc", "passwd"])); 
} 

Playground

+0

權衡是你canno t在單個呼叫中有多種類型。 – Shepmaster