Chapter 05

PathBuf と &Path

ほげさん
ほげさん
2023.02.28に更新

このページでは Rust でパス操作時に使われるパス文字列型を理解するために PathBuf&Path についてまとめる。

OsString と PathBuf の違い

StringOsStringVec<u8> に関する制限に差があったが、OsStringPathBuf の間にそのような違いはない。

そもそも PathBufOsString をそのまま保持している。

path.rs
pub struct PathBuf {
    inner: OsString,
}

OsStringPathBuf の違いはシンプルで、パス操作に特化した処理があるかないかだけだ。

たとえば 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 の関係も PathBufOsString の関係と同様だ。

つまり Path は内部には OsStr を持っているし、

path.rs
pub struct Path {
    inner: OsStr,
}

PathBuf&Path は相互に変換できる。

let path: &Path = &path_buf;
let path_buf: PathBuf = path.to_path_buf();

整理

  • PathBufOsString を直接保持する構造体
  • PathBufOsString にパス関係の処理を追加しただけのもの
  • PathBuf&Path の相互変換は容易

参考

https://doc.rust-jp.rs/rust-by-example-ja/std_misc/path.html