Rust에도 Ruby의 Pathname 같은 도서관이 있어요.

나는 Rust가 Ruby Pathname과 같은 초편의 라이브러리가 없을 것이라고 생각한다. 파일 이름을 매개 변수에 전달하는 것이 아니라, 파일 이름을 수신기로 여러 가지 방법을 부르는 것이다.(반갑다)

문자열로만 구조를 확인하는 시스템


Path::new("/aa/bb/cc.tar.gz").is_absolute() // => true
Path::new("cc.tar.gz").is_relative()        // => true
Path::new("/aa/bb/cc.tar.gz").has_root()    // => true
Path::new("/aa/bb/cc.tar.gz").starts_with("/aa/bb")  // => true
Path::new("/aa/bb/cc.tar.gz").ends_with("cc.tar.gz") // => true
는 문자열이지만 위젯의 경계를 무시할 수 없습니다.starts_with("/a"), ends_with("gz") 등이 가짜가 됐다.

부품 확보 시스템


Path::new("/aa/bb/cc.tar.gz").extension()   // => Some("gz")
Path::new("/aa/bb/cc.tar.gz").file_name()   // => Some("cc.tar.gz")
Path::new("/aa/bb/cc.tar.gz").file_stem()   // => Some("cc.tar")
Path::new("/aa/bb/cc.tar.gz").file_prefix() // => Some("cc")
Path::new("/aa/bb/cc.tar.gz").parent()      // => Some("/aa/bb")
stem은'나무 줄기'라는 뜻인 것 같아요.
확장자의 파일 이름을 명확하게 생략하는 방법은 매우 어렵다.
루비에서는 분명히 자주 사용하지만 basename(".*")처럼 써야 하기 때문에 보기 싫다.

모든 부품을 순서대로 가져오는 시스템


Path::new("/aa/bb/cc.tar.gz").ancestors().collect::<Vec<_>>()  // => ["/aa/bb/cc.tar.gz", "/aa/bb", "/aa", "/"]
Path::new("/aa/bb/cc.tar.gz").components().collect::<Vec<_>>() // => [RootDir, Normal("aa"), Normal("bb"), Normal("cc.tar.gz")]
Path::new("/aa/bb/cc.tar.gz").iter().collect::<Vec<_>>()       // => ["/", "aa", "bb", "cc.tar.gz"]
컴포니언츠는 조금 무관심한 느낌이지만 Rust는 엔움이 열거한 정의대로 랩으로 직접 싸서 쉽게 하는 경향이 있다.

경로 생성/조정 시스템


// パスを追加していく(よく使う)
Path::new("/aa").join("bb").join("cc.tar.gz")         // => "/aa/bb/cc.tar.gz"

// ファイル名・拡張子の置き換え
Path::new("/aa/bb/cc.tar.gz").with_file_name("xxx")   // => "/aa/bb/xxx"
Path::new("/aa/bb/cc.tar.gz").with_extension("xxx")   // => "/aa/bb/cc.tar.xxx"
  
// 祖先のディレクトリ除去
Path::new("/aa/bb/cc.tar.gz").strip_prefix("/aa/bb")  // => Ok("cc.tar.gz")
새로운 Path형 인스턴스를 돌려줄 수 있어서 사용하기 편해요.

파일 시스템에 잠깐 액세스하는 시스템


Path::new("/bin").exists()      // => true
Path::new("/bin").try_exists()  // => Ok(true)
Path::new("/bin/cat").is_file() // => true
Path::new("/bin").is_dir()      // => true
Path::new("/etc").is_symlink()  // => true
방법 명칭은 통속적이고 알기 쉽다.

파일 시스템에 대한 액세스가 큰 시스템


Path::new("/etc").metadata()         // => Ok(Metadata { file_type: FileType(FileType { mode: 16877 }), is_dir: true, is_file: false, permissions: Permissions(FilePermissions { mode: 16877 }), modified: Ok(SystemTime { tv_sec: 1646948709, tv_nsec: 53641797 }), accessed: Ok(SystemTime { tv_sec: 1646964920, tv_nsec: 777256864 }), created: Ok(SystemTime { tv_sec: 1577865600, tv_nsec: 0 }), .. })
Path::new("/etc").symlink_metadata() // => Ok(Metadata { file_type: FileType(FileType { mode: 41453 }), is_dir: false, is_file: false, permissions: Permissions(FilePermissions { mode: 41453 }), modified: Ok(SystemTime { tv_sec: 1577865600, tv_nsec: 0 }), accessed: Ok(SystemTime { tv_sec: 1577865600, tv_nsec: 0 }), created: Ok(SystemTime { tv_sec: 1577865600, tv_nsec: 0 }), .. })
Path::new("/etc").read_link()        // => Ok("private/etc")
Path::new("/etc").read_dir().unwrap().take(2).collect::<Vec<_>>() // => [Ok(DirEntry("/etc/kcpassword")), Ok(DirEntry("/etc/hosts~"))]
중요한 거 없어요glob?

귀일화


// . を含むパスを正規化する
Path::new("/usr/bin/..").canonicalize()    // => Ok("/usr")
Path::new("../../../../..").canonicalize() // => Ok("/Users")
문자열 조작뿐만 아니라 파일 시스템의 구조도 실제에서 볼 수 있다.~/ 전개되지 않았다.

유형 변환


// 表示する用の文字列 (メソッド名にかなり違和感はある)
Path::new("/aa/bb/cc.tar.gz").display()         // => "/aa/bb/cc.tar.gz"

// 全然違いがわからないけど std::ffi::OsStr 型になっている
Path::new("/aa/bb/cc.tar.gz").as_os_str()       // => "/aa/bb/cc.tar.gz"

// 不正な文字があると失敗する版
Path::new("/aa/bb/cc.tar.gz").to_str()          // => Some("/aa/bb/cc.tar.gz")

// 不正な文字は無視して強行する版
Path::new("/aa/bb/cc.tar.gz").to_string_lossy() // => "/aa/bb/cc.tar.gz"

// PathBuf 型にする
let path = Path::new("/aa/bb/cc.tar.gz").to_path_buf();
std::any::type_name_of_val(&path)               // => "std::path::PathBuf"

PathBuf형이 되면 자신을 갱신할 수 있어요.


let mut path = PathBuf::new();
path.push("/");
path.push("aa");
path.push("xx");
path // => "/aa/xx"
path.pop();
path // => "/aa"
path.push("bb");
path // => "/aa/bb"
path.push("xxx.txt");
path // => "/aa/bb/xxx.txt"

// set_file_name はいったん pop して push するのと同等っぽい
path.set_file_name("cc.tar.xx");
path // => "/aa/bb/cc.tar.xx"

path.set_extension("gz");
  
// 完成
path // => "/aa/bb/cc.tar.gz"
// 更新が終わったら Path 型に戻しておこう  
let path = path.as_path();
std::any::type_name_of_val(path) // => "std::path::Path"
Path형만 사용하면 유연하게 조작할 수 있기 때문에 PathBuf는 잘 사용하지 않습니다.

이야기 전개할 녀석 없나?


Ruby
Pathname("~/").expand_path # => "/Users/alice"
나는 이것을 하고 싶지만 대응하는 방법을 찾지 못했다.
플랫폼에 의존하기 때문에 표준적인 준비가 없을 수도 있다.

좋은 웹페이지 즐겨찾기