2016-11-12 103 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