このページでは Rust でパス操作時に使われるパス文字列型を理解するために PathBuf
と &Path
についてまとめる。
OsString と PathBuf の違い
String
と OsString
は Vec<u8>
に関する制限に差があったが、OsString
と PathBuf
の間にそのような違いはない。
そもそも PathBuf
は OsString
をそのまま保持している。
pub struct PathBuf {
inner: OsString,
}
OsString
と PathBuf
の違いはシンプルで、パス操作に特化した処理があるかないかだけだ。
たとえば PathBuf
には文字列をパスとして結合する join
などが用意されており、ファイルシステムのことを気にしないでパス文字列を操作できるようになっている。
let path_buf: PathBuf = PathBuf::from("prod");
let path_buf: PathBuf = path_buf.join("app.log"); // prod/app.log
ほかにも「ファイル名」や「親ディレクトリ名」や「拡張子」を取得したりと、/
や .
で分割するといった文字列操作ではなく直感的なパス操作の処理が用意されている。
let path_buf: PathBuf = PathBuf::from("prod");
let path_buf: PathBuf = path_buf.join("app.log"); // prod/app.log
println!("{:?}", path_buf.file_name()); // app.log
println!("{:?}", path_buf.parent()); // prod
println!("{:?}", path_buf.extension()); // .log
余談 存在チェック
PathBuf
はあくまでも文字列なので、ファイルの存在とはなんら関係ない。
ファイルの存在と関係するのは File
という型の方で、こちらは生成時にファイルの存在に応じて io::Result<File>
になる。
let file: io::Result<File> = File::open("/tmp");
// Ok(File { fd: 3, path: "/private/tmp", read: true, write: false })
let file: io::Result<File> = File::open("/foo");
// Err(Os { code: 2, kind: NotFound, message: "No such file or directory" })
PathBuf を見かけるタイミング
現在の作業ディレクトリを取得する current_dir
などは、Result<PathBuf>
を返す。
let path_buf: io::Result<PathBuf> = current_dir();
また、read_dir
の返すイテレータで DirEntry
を扱うときに、path
で取得できる値は PathBuf
である。
PathBuf と &Path の違い
PathBuf
と &Path
の関係は OsString
と &OsStr
と同様だし、&Path
と &OsStr
の関係も PathBuf
と OsString
の関係と同様だ。
つまり Path
は内部には OsStr
を持っているし、
pub struct Path {
inner: OsStr,
}
PathBuf
と &Path
は相互に変換できる。
let path: &Path = &path_buf;
let path_buf: PathBuf = path.to_path_buf();
整理
-
PathBuf
はOsString
を直接保持する構造体 -
PathBuf
はOsString
にパス関係の処理を追加しただけのもの -
PathBuf
と&Path
の相互変換は容易
参考