Drop
Drop 트레이트는 drop이라는 하나의 메서드만을 가집니다. 이 메서드는 객체가 스코프를 벗어날 때 자동으로 호출됩니다. Drop 트레이트의 주요 용도는 구현체 인스턴스가 소유한 리소스를 해제하는 것입니다.
Box, Vec, String, File, 그리고 Process는 리소스를 해제하기 위해 Drop 트레이트를 구현하는 몇 가지 타입의 예입니다. Drop 트레이트는 임의의 사용자 정의 데이터 타입에 대해 수동으로 구현될 수도 있습니다.
다음 예제는 drop 함수가 호출될 때 알림을 주기 위해 콘솔 출력을 추가합니다.
struct Droppable {
name: &'static str,
}
// 이 간단한 `drop` 구현은 콘솔에 출력을 추가합니다.
impl Drop for Droppable {
fn drop(&mut self) {
println!("> {}를 해제합니다", self.name);
}
}
fn main() {
let _a = Droppable { name: "a" };
// 블록 A
{
let _b = Droppable { name: "b" };
// 블록 B
{
let _c = Droppable { name: "c" };
let _d = Droppable { name: "d" };
println!("블록 B를 나가는 중");
}
println!("방금 블록 B를 나갔습니다");
println!("블록 A를 나가는 중");
}
println!("방금 블록 A를 나갔습니다");
// 변수는 `drop` 함수를 사용하여 수동으로 해제할 수 있습니다.
drop(_a);
// TODO ^ 이 줄을 주석 처리해 보세요.
println!("메인 함수 끝");
// `_a`는 여기서 다시 `drop`되지 않습니다. 이미 (수동으로) `drop`되었기 때문입니다.
}
더 실용적인 예로, Drop 트레이트를 사용하여 더 이상 필요하지 않은 임시 파일을 자동으로 정리하는 방법은 다음과 같습니다:
use std::fs::File;
use std::path::PathBuf;
struct TempFile {
file: File,
path: PathBuf,
}
impl TempFile {
fn new(path: PathBuf) -> std::io::Result<Self> {
// 참고: `File::create()`는 기존 파일을 덮어씁니다.
let file = File::create(&path)?;
Ok(Self { file, path })
}
}
// `TempFile`이 drop될 때:
// 1. 먼저, 우리가 작성한 drop 구현이 파일 시스템에서 파일 이름을 제거합니다.
// 2. 그런 다음, `File`의 drop이 파일을 닫고 디스크에서 기본 콘텐츠를 제거합니다.
impl Drop for TempFile {
fn drop(&mut self) {
if let Err(e) = std::fs::remove_file(&self.path) {
eprintln!("임시 파일을 제거하는 데 실패했습니다: {}", e);
}
println!("> 임시 파일을 해제했습니다: {:?}", self.path);
// `File`의 drop은 이 구조체의 필드이므로 여기서 암시적으로 호출됩니다.
}
}
fn main() -> std::io::Result<()> {
// drop 동작을 시연하기 위해 새 스코프를 생성합니다.
{
let temp = TempFile::new("test.txt".into())?;
println!("임시 파일이 생성되었습니다");
// `temp`가 스코프를 벗어날 때 파일이 자동으로 정리됩니다.
}
println!("스코프 종료 - 파일이 정리되어야 합니다");
// 필요하다면 수동으로 drop할 수도 있습니다.
let temp2 = TempFile::new("another_test.txt".into())?;
drop(temp2); // 파일을 명시적으로 drop합니다.
println!("수동으로 파일을 drop했습니다");
Ok(())
}