尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

【Rust中级教程】2.8. API设计原则之灵活性(flexible) Pt.4:显式析构函数的问题及3种解决方案

【Rust中级教程】2.8. API设计原则之灵活性(flexible) Pt.4:显式析构函数的问题及3种解决方案
📅 发布时间:2026/7/24 20:46:11

2.8. API设计原则之灵活性(flexible) Pt.4:显式析构函数的问题及3种解决方案

2.8.1. 显式析构函数的问题

添加显式析构函数时会遇到问题:
- 当某一类型实现了Drop,在析构函数中无法将该类型的任何字段移出。因为在显式析构函数运行后,drop()仍会被调用,它接受&mut self,要求self的所有部分都没被移动。
-Drop接收的是&mut self而不是self,因此Drop无法实现简单地调用显式析构函数并忽略其结果(因为Drop不拥有self)

以上一篇文章的例子为基础,如果我们加上既实现了Droptrait,又写了close方法:

use std::os::fd::{FromRawFd, IntoRawFd}; use std::fs::{File as StdFile, OpenOptions, metadata}; use std::io::Error; /// 一个表示文件句柄的类型 struct File { /// 文件名 name: String, /// 文件描述符 fd: i32, } impl File { /// 一个构造函数,打开一个文件并返回一个 File 实例 fn open(name: &str) -> Result<File, Error> { // 使用 OpenOptions 打开文件,具备读写权限 let file: StdFile = OpenOptions::new() .read(true) .write(true) .open(name)?; // 获取文件描述符 let fd: i32 = file.into_raw_fd(); // 返回一个 File 实例 Ok(File { name: name.to_string(), fd, }) } /// 一个显式的析构函数,关闭文件并返回任何错误 fn close(self) -> Result<(), Error> { // 使用 FromRawFd 将 fd 转换回 File let file: std::fs::File = unsafe { std::fs::File::from_raw_fd(self.fd) }; // 刷新文件数据到磁盘 file.sync_all()?; // 将文件截断为 0 字节 file.set_len(0)?; // 再次刷新文件 file.sync_all()?; // 丢弃文件实例,它会自动关闭文件 drop(file); // 返回成功 Ok(()) } } //实现drop trait impl Drop for File { fn drop(&mut self) { let _ = self.close(); //调用close方法来丢弃 println!("File dropped"); } } fn main() { // 创建一个名为 "test.txt" 的文件,并写入一些内容 std::fs::write("test.txt", "Hello, world!").unwrap(); // 打开文件并获取 File 实例 let file: File = File::open("test.txt").unwrap(); // 打印文件名和 fd println!("File name: {}, fd: {}", file.name, file.fd); // 关闭文件并处理任何错误 match file.close() { Ok(()) => println!("File closed successfully"), Err(e) => println!("Error closing file: {}", e), } // 检查关闭后的文件大小 let metadata = metadata("test.txt").unwrap(); println!("File size: {} bytes", metadata.len()); }

输出:

error[E0507]: cannot move out of `*self` which is behind a mutable reference --> src/main.rs:59:17 | 59 | let _ = self.close(); //调用close方法来丢弃 | ^^^^ ------- `*self` moved due to this method call | | | move occurs because `*self` has type `File`, which does not implement the `Copy` trait | note: `File::close` takes ownership of the receiver `self`, which moves `*self` --> src/main.rs:33:14 | 33 | fn close(self) -> Result<(), Error> { | ^^^^ note: if `File` implemented `Clone`, you could clone the value --> src/main.rs:6:1 | 6 | struct File { | ^^^^^^^^^^^ consider implementing `Clone` for this type ... 59 | let _ = self.close(); //调用close方法来丢弃 | ---- you could clone this value

报错信息显示无法从*self中移出值,因为它位于&mut self后面。

2.8.2. 解决方案

首先需要说明的是没有完美的解决方案,我们只能尽力弥补。


解决方案1:把结构体包装Option<T>里然后再套一层结构体

我们可以将顶层方案作为包装了Option<T>的新类型,这样Option<T>内部持有一个类型,这个类型包含所有的字段。

这个时候我们就需要两个析构函数,外边一个里面一个。在这两个析构函数中使用Option::take函数来获取数据所有权从而移除值。

由于内部类型没有实现Drop,所以你可以获取所有字段的所有权。

缺点:想在顶层类型上提供的所有方法,现在都必须添加通过Option<T>这层壳来获取内部类型上字段的代码。

我们在上文的代码例基础上进行修改:

步骤1:改掉File的定义,套一层壳

首先我们得把两个字段移到另一个结构体里,套在Option<T>中作为File结构体的字段

/// 一个表示文件句柄的类型 struct InnerFile { /// 文件名 name: String, /// 文件描述符 fd: i32, } /// 给InnerFile套了一个壳 struct File { /// 把InnerFile包装在Option<T>中 inner: Option<InnerFile>, }
步骤2:修改File上的方法

File上有两个方法,我们都需要添加通过Option<T>这层壳来获取内部类型上字段的代码。

首先是open方法:

/// 一个构造函数,打开一个文件并返回一个 File 实例 fn open(name: &str) -> Result<File, Error> { // 使用 OpenOptions 打开文件,具备读写权限 let file: StdFile = OpenOptions::new() .read(true) .write(true) .open(name)?; // 获取文件描述符 let fd: i32 = file.into_raw_fd(); // 返回一个 File 实例 Ok(File { inner: Some( InnerFile { name: name.to_string(), fd, }) }) }
  • 由于这个代码只有返回值设计了File结构体,所以也只有返回值需要改

接下来是close方法:

/// 一个显式的析构函数,关闭文件并返回任何错误 fn close(mut self) -> Result<(), Error> { // 记得self要变为mut self,否则take不了 // 使用模式匹配提取出字段的值 if let Some(inner) = self.inner.take() { let name = inner.name; let fd = inner.fd; println!("Closing file: {} with fd: {}", name, fd); // 使用 FromRawFd 将 fd 转换回 File let file: std::fs::File = unsafe { std::fs::File::from_raw_fd(fd) }; // 刷新文件数据到磁盘 file.sync_all()?; // 将文件截断为 0 字节 file.set_len(0)?; // 再次刷新文件 file.sync_all()?; // 丢弃文件实例,它会自动关闭文件 drop(file); // 返回成功 Ok(()) } else { // 如果inner字段是None,说明文件已经被关闭或丢弃,返回错误 Err(Error::new( std::io::ErrorKind::Other, "File is already closed", )) } }
  • 参数传进去之后先得通过模式匹配来获取字段的值
  • 如果如果inner字段是None,也就是模式匹配不成功的情况下,我们需要自己写一个错误返回
步骤3:修改Droptrait的实现

Drop::drop方法需要修改:

fn drop(&mut self) { // 使用模式匹配获取字段值 if let Some(inner) = self.inner.take() { let name = inner.name; let fd = inner.fd; println!("Dropping file: {} (fd: {})", name, fd); // 使用 FromRawFd 将 fd 转换回 File let file: std::fs::File = unsafe { std::fs::File::from_raw_fd(fd) }; // 丢弃file实例 drop(file); } else { // 如果inner字段是None的话,说明文件已经被丢弃或关闭,不做任何操作 } }
  • 参数传进去之后先得通过模式匹配来获取字段的值
  • 如果inner字段是None的话,说明文件已经被丢弃或关闭,不做任何操作
步骤4:微修主函数

主函数中需要提取字段值的地方需要修改:

fn main() { // ...前文无修改,已省略 // 打印文件名和 fd (这里需要修改) println!("File name: {}, fd: {}", file.inner.as_ref().unwrap().name, file.inner.as_ref().unwrap().fd ); // ...后文无修改,已省略 }
  • 原始类型是Option<InnerFile>,调用.as_ref()后变成Option<&InnerFile>
  • 变成了Option<&InnerFile>再使用unwrap提取出来的值就是引用而不是所有的值
  • file.inner是一个Option<InnerFile>类型。而直接访问Option的值需要转移所有权或匹配处理(例如通过take()或unwrap()),这会销毁Option的内部值,所以得要as_ref
整体代码
use std::os::fd::{FromRawFd, IntoRawFd}; use std::fs::{File as StdFile, OpenOptions, metadata}; use std::io::Error; /// 一个表示文件句柄的类型 struct InnerFile { /// 文件名 name: String, /// 文件描述符 fd: i32, } /// 给InnerFile套了一个壳 struct File { /// 把InnerFile包装在Option<T>中 inner: Option<InnerFile>, } impl File { /// 一个构造函数,打开一个文件并返回一个 File 实例 fn open(name: &str) -> Result<File, Error> { // 使用 OpenOptions 打开文件,具备读写权限 let file: StdFile = OpenOptions::new() .read(true) .write(true) .open(name)?; // 获取文件描述符 let fd: i32 = file.into_raw_fd(); // 返回一个 File 实例 Ok(File { inner: Some( InnerFile { name: name.to_string(), fd, }) }) } /// 一个显式的析构函数,关闭文件并返回任何错误 fn close(mut self) -> Result<(), Error> { // 记得self要变为mut self,否则take不了 // 使用模式匹配提取出字段的值 if let Some(inner) = self.inner.take() { let name = inner.name; let fd = inner.fd; println!("Closing file: {} with fd: {}", name, fd); // 使用 FromRawFd 将 fd 转换回 File let file: std::fs::File = unsafe { std::fs::File::from_raw_fd(fd) }; // 刷新文件数据到磁盘 file.sync_all()?; // 将文件截断为 0 字节 file.set_len(0)?; // 再次刷新文件 file.sync_all()?; // 丢弃文件实例,它会自动关闭文件 drop(file); // 返回成功 Ok(()) } else { // 如果inner字段是None,说明文件已经被关闭或丢弃,返回错误 Err(Error::new( std::io::ErrorKind::Other, "File is already closed", )) } } } // 实现drop trait,用于在值离开作用域时运行的一些代码 impl Drop for File { fn drop(&mut self) { // 使用模式匹配获取字段值 if let Some(inner) = self.inner.take() { let name = inner.name; let fd = inner.fd; println!("Dropping file: {} (fd: {})", name, fd); // 使用 FromRawFd 将 fd 转换回 File let file: std::fs::File = unsafe { std::fs::File::from_raw_fd(fd) }; // 丢弃file实例 drop(file); } else { // 如果inner字段是None的话,说明文件已经被丢弃或关闭,不做任何操作 } } } fn main() { // 创建一个名为 "test.txt" 的文件,并写入一些内容 std::fs::write("test.txt", "Hello, world!").unwrap(); // 打开文件并获取 File 实例 let file: File = File::open("test.txt").unwrap(); // 打印文件名和 fd (这里需要修改) println!("File name: {}, fd: {}", file.inner.as_ref().unwrap().name, file.inner.as_ref().unwrap().fd ); // 关闭文件并处理任何错误 match file.close() { Ok(()) => println!("File closed successfully"), Err(e) => println!("Error closing file: {}", e), } // 检查关闭后的文件大小 let metadata = metadata("test.txt").unwrap(); println!("File size: {} bytes", metadata.len()); }

解决方案2:把字段包装在Option<T>里

我们也可以保持结构体不变,把每个字段的值都套在Option<T>里,需要获取所有权使用时用Option::take就可以,需要引用时用.as_ref()加.unwrap()就可以。

如果类型具有合理的空值,那么效果很好。

缺点:如果你必须将几乎每个字段都包装在Option中,然后对这些字段的每次访问都进行匹配的unwrap就会使代码变得很繁琐。

我们在上文的代码例基础上进行修改:

步骤1:改掉File的定义

为每一个字段添加一层Option<T>:

/// 一个表示文件句柄的类型 struct File { /// 文件名 name: Option<String>, /// 文件描述符 fd: Option<i32>, }
步骤2:修改File上的方法

File上有两个方法,我们都需要添加通过Option<T>这层壳来获取内部类型上字段的代码。

首先是open方法:

/// 一个构造函数,打开一个文件并返回一个 File 实例 fn open(name: &str) -> Result<File, Error> { // 使用 OpenOptions 打开文件,具备读写权限 let file: StdFile = OpenOptions::new() .read(true) .write(true) .open(name)?; // 获取文件描述符 let fd: i32 = file.into_raw_fd(); // 返回一个 File 实例 Ok(File { name: Some(name.to_string()), fd: Some(fd), }) }
  • open方法的参数没有涉及到File结构体,所以接收参数部分不用修改
  • open方法的返回值涉及到了File,得为每个字段添上Some变体

其次是close方法:

/// 一个显式的析构函数,关闭文件并返回任何错误 fn close(mut self) -> Result<(), Error> { // 模式匹配,并使用std::mem::take取出name字段的值 if let Some(name) = std::mem::take(&mut self.name) { //模式匹配,并使用std::mem::take取出fd字段的值 if let Some(fd) = std::mem::take(&mut self.fd) { // 打印 println!("Closing file: {} with fd: {}", name, fd); // 使用 FromRawFd 将 fd 转换回 File let file: std::fs::File = unsafe { std::fs::File::from_raw_fd(fd) }; // 刷新文件数据到磁盘 file.sync_all()?; // 将文件截断为 0 字节 file.set_len(0)?; // 再次刷新文件 file.sync_all()?; // 丢弃文件实例,它会自动关闭文件 drop(file); // 返回成功 Ok(()) } else { // 如果fd字段是None,说明文件已经被关闭或丢弃,返回一个错误 Err(Error::new( std::io::ErrorKind::Other, "File descriptor already dropped or taken", )) } } else { // 如果name字段是None,说明文件已经被关闭或丢弃,返回一个错误 Err(Error::new( std::io::ErrorKind::Other, "File name already dropped or taken", )) } }
  • 参数要先经过模式匹配,并使用std::mem::take取出里面的值
  • 如果任意字段是None,说明文件已经被关闭或丢弃,返回一个错误
步骤3:修改Droptrait的实现
fn drop(&mut self) { // 使用模式匹配获取字段值 if let Some(name) = self.name.take() { if let Some(fd) = self.fd.take() { println!("Dropping file: {} (fd: {})", name, fd); // 使用 FromRawFd 将 fd 转换回 let file: std::fs::File = unsafe { std::fs::File::from_raw_fd(fd) }; // 丢弃file实例 drop(file); } else { // 如果fd字段是None,说明文件已经被关闭或丢弃,不做任何操作 } } else { // 如果name字段是None,说明文件已经被关闭或丢弃,不做任何操作 } }
  • 参数要先经过模式匹配,并使用std::mem::take取出里面的值
  • 如果任意字段是None,说明文件已经被关闭或丢弃,不做任何操作
步骤4:微修主函数
fn main() { // ...前文无修改,已省略 // 打印文件名和 fd (这里需要修改) println!("File name: {}, fd: {}", file.name.as_ref().unwrap(), file.fd.as_ref().unwrap() ); // ...后文无修改,已省略 }
  • 原始类型被Option<T>包裹,调用.as_ref()后获得里面值的引用
  • 变成了引用之后再使用unwrap提取出来的值就是引用而不是所有的值
  • 而直接访问Option的值需要转移所有权或匹配处理(例如通过take()或unwrap()),这会销毁Option的内部值,所以得要as_ref
整体代码
use std::os::fd::{FromRawFd, IntoRawFd}; use std::fs::{File as StdFile, OpenOptions, metadata}; use std::io::Error; /// 一个表示文件句柄的类型 struct File { /// 文件名 name: Option<String>, /// 文件描述符 fd: Option<i32>, } impl File { /// 一个构造函数,打开一个文件并返回一个 File 实例 fn open(name: &str) -> Result<File, Error> { // 使用 OpenOptions 打开文件,具备读写权限 let file: StdFile = OpenOptions::new() .read(true) .write(true) .open(name)?; // 获取文件描述符 let fd: i32 = file.into_raw_fd(); // 返回一个 File 实例 Ok(File { name: Some(name.to_string()), fd: Some(fd), }) } /// 一个显式的析构函数,关闭文件并返回任何错误 fn close(mut self) -> Result<(), Error> { // 模式匹配,并使用使用std::mem::take取出name字段的值 if let Some(name) = std::mem::take(&mut self.name) { //模式匹配,并使用使用std::mem::take取出fd字段的值 if let Some(fd) = std::mem::take(&mut self.fd) { // 打印 println!("Closing file: {} with fd: {}", name, fd); // 使用 FromRawFd 将 fd 转换回 File let file: std::fs::File = unsafe { std::fs::File::from_raw_fd(fd) }; // 刷新文件数据到磁盘 file.sync_all()?; // 将文件截断为 0 字节 file.set_len(0)?; // 再次刷新文件 file.sync_all()?; // 丢弃文件实例,它会自动关闭文件 drop(file); // 返回成功 Ok(()) } else { // 如果fd字段是None,说明文件已经被关闭或丢弃,返回一个错误 Err(Error::new( std::io::ErrorKind::Other, "File descriptor already dropped or taken", )) } } else { // 如果name字段是None,说明文件已经被关闭或丢弃,返回一个错误 Err(Error::new( std::io::ErrorKind::Other, "File name already dropped or taken", )) } } } // 实现drop trait,用于在值离开作用域时运行的一些代码 impl Drop for File { fn drop(&mut self) { // 使用模式匹配获取字段值 if let Some(name) = self.name.take() { if let Some(fd) = self.fd.take() { println!("Dropping file: {} (fd: {})", name, fd); // 使用 FromRawFd 将 fd 转换回 let file: std::fs::File = unsafe { std::fs::File::from_raw_fd(fd) }; // 丢弃file实例 drop(file); } else { // 如果fd字段是None,说明文件已经被关闭或丢弃,不做任何操作 } } else { // 如果name字段是None,说明文件已经被关闭或丢弃,不做任何操作 } } } fn main() { // 创建一个名为 "test.txt" 的文件,并写入一些内容 std::fs::write("test.txt", "Hello, world!").unwrap(); // 打开文件并获取 File 实例 let file: File = File::open("test.txt").unwrap(); // 打印文件名和 fd (这里需要修改) println!("File name: {}, fd: {}", file.name.as_ref().unwrap(), file.fd.as_ref().unwrap() ); // 关闭文件并处理任何错误 match file.close() { Ok(()) => println!("File closed successfully"), Err(e) => println!("Error closing file: {}", e), } // 检查关闭后的文件大小 let metadata = metadata("test.txt").unwrap(); println!("File size: {} bytes", metadata.len()); }

方法3:将数据持有在ManuallyDrop类型内

将数据持有在ManuallyDrop类型内,它会解引用内部类型,不必再使用unwrap。

在drop中进行销毁时,可使用ManuallyDrop::take来获取所有权。

缺点:ManuallyDrop::take是不安全的,需要放在unsafe块中。

我们在上文的代码例基础上进行修改:

步骤1:改掉File的定义

为每一个字段添加一层ManuallyDrop:

/// 一个表示文件句柄的类型 struct File { /// 文件名 name: ManuallyDrop<String>, /// 文件描述符 fd: ManuallyDrop<i32>, }
步骤2:修改File上的方法

File上有两个方法,我们都需要添加通过ManuallyDrop这层壳来获取内部类型上字段的代码。

首先是open方法:

/// 一个构造函数,打开一个文件并返回一个 File 实例 fn open(name: &str) -> Result<File, Error> { // 使用 OpenOptions 打开文件,具备读写权限 let file: StdFile = OpenOptions::new() .read(true) .write(true) .open(name)?; // 取得文件描述符的所有权 let fd: i32 = file.into_raw_fd(); // 返回一个 File 实例 Ok(File { name: ManuallyDrop::new(name.to_string()), fd: ManuallyDrop::new(fd), }) }
  • open方法的参数没有涉及到File结构体,所以接收参数部分不用修改
  • open方法的返回值涉及到了File,每个字段都得用ManuallyDrop::new来传值

其次是close方法:

/// 一个显式的析构函数,关闭文件并返回任何错误 fn close(mut self) -> Result<(), Error> { // 使用std::mem::replace将name字段替换为一个空字符串,把原来的值给name let name = std::mem::replace(&mut self.name, ManuallyDrop::new("".to_string())); // 使用std::mem::replace将fd字段替换为一个无效的值(-1),把原来的值给fd let fd = std::mem::replace(&mut self.fd, ManuallyDrop::new(-1)); // 打印 println!("Closing file: {:?} with fd: {:?}", name, fd); // 使用 FromRawFd 将 fd 转换回 File let file: std::fs::File = unsafe { std::fs::File::from_raw_fd(*fd) //这里fd要先解引用 }; // 刷新文件数据到磁盘 file.sync_all()?; // 将文件截断为 0 字节 file.set_len(0)?; // 再次刷新文件 file.sync_all()?; // 丢弃文件实例,它会自动关闭文件 drop(file); // 返回成功 Ok(()) }
  • 使用std::mem::replace将name字段替换为一个空字符串,把原来的值给name
  • 使用std::mem::replace将fd字段替换为一个无效的值(-1),把原来的值给fd
  • std::fs::File::from_raw_fd(*fd)中参数要先解引用,也就是写*fd
步骤3:修改Droptrait的实现
fn drop(&mut self) { // 使用ManuallyDrop::take取出name字段的值,并检查是否是空字符串 let name = unsafe { ManuallyDrop::take(&mut self.name) }; // 使用ManuallyDrop::take取出fd字段的值,并检查是否是无效的值 let fd = unsafe { ManuallyDrop::take(&mut self.fd) }; //打印 println!("Dropping file: {:?} (fd: {:?})", name, fd); // 如果fd字段不是无效的值,说明文件还没有被关闭或丢弃,需要执行丢弃操作 if fd != -1 || !name.is_empty() { let file = unsafe { std::fs::File::from_raw_fd(fd) }; // 丢弃 drop(file); } }
  • 使用ManuallyDrop::take取出name和fd字段的值,并检查是否是空字符串或无效的值
  • 如果fd字段不是无效的值(不是-1),或是name字段不是空字符串,就说明文件还没有被关闭或丢弃,需要执行丢弃操作
  • 其实这里不用两个判断条件(fd != -1 || !name.is_empty()),一个就够了,因为name和fd字段的值的变化是一起的,一个无效就代表着整个结构体都还未被清理。
步骤4:微修主函数
fn main() { // ...前文无修改,已省略 // 打印文件名和 fd (这里需要修改) println!("File name: {}, fd: {}", *file.name, *file.fd); // ...后文无修改,已省略 }
  • 使用解引用来打印值
整体代码
use std::os::fd::{FromRawFd, IntoRawFd}; use std::fs::{File as StdFile, OpenOptions, metadata}; use std::io::Error; use std::mem::ManuallyDrop; /// 一个表示文件句柄的类型 struct File { /// 文件名 name: ManuallyDrop<String>, /// 文件描述符 fd: ManuallyDrop<i32>, } impl File { /// 一个构造函数,打开一个文件并返回一个 File 实例 fn open(name: &str) -> Result<File, Error> { // 使用 OpenOptions 打开文件,具备读写权限 let file: StdFile = OpenOptions::new() .read(true) .write(true) .open(name)?; // 获取文件描述符 let fd: i32 = file.into_raw_fd(); // 返回一个 File 实例 Ok(File { name: ManuallyDrop::new(name.to_string()), fd: ManuallyDrop::new(fd), }) } /// 一个显式的析构函数,关闭文件并返回任何错误 fn close(mut self) -> Result<(), Error> { // 使用std::mem::replace将name字段替换为一个空字符串,把原来的值给name let name = std::mem::replace(&mut self.name, ManuallyDrop::new("".to_string())); // 使用std::mem::replace将fd字段替换为一个无效的值(-1),把原来的值给fd let fd = std::mem::replace(&mut self.fd, ManuallyDrop::new(-1)); // 打印 println!("Closing file: {:?} with fd: {:?}", name, fd); // 使用 FromRawFd 将 fd 转换回 File let file: std::fs::File = unsafe { std::fs::File::from_raw_fd(*fd) //这里fd要先解引用 }; // 刷新文件数据到磁盘 file.sync_all()?; // 将文件截断为 0 字节 file.set_len(0)?; // 再次刷新文件 file.sync_all()?; // 丢弃文件实例,它会自动关闭文件 drop(file); // 返回成功 Ok(()) } } // 实现drop trait,用于在值离开作用域时运行的一些代码 impl Drop for File { fn drop(&mut self) { // 使用ManuallyDrop::take取出name字段的值,并检查是否是空字符串 let name = unsafe { ManuallyDrop::take(&mut self.name) }; // 使用ManuallyDrop::take取出fd字段的值,并检查是否是无效的值 let fd = unsafe { ManuallyDrop::take(&mut self.fd) }; //打印 println!("Dropping file: {:?} (fd: {:?})", name, fd); // 如果fd字段不是无效的值,说明文件还没有被关闭或丢弃,需要执行丢弃操作 if fd != -1 || !name.is_empty() { let file = unsafe { std::fs::File::from_raw_fd(fd) }; // 丢弃 drop(file); } } } fn main() { // 创建一个名为 "test.txt" 的文件,并写入一些内容 std::fs::write("test.txt", "Hello, world!").unwrap(); // 打开文件并获取 File 实例 let file: File = File::open("test.txt").unwrap(); // 打印文件名和 fd (这里需要修改) println!("File name: {}, fd: {}", *file.name, *file.fd); // 关闭文件并处理任何错误 match file.close() { Ok(()) => println!("File closed successfully"), Err(e) => println!("Error closing file: {}", e), } // 检查关闭后的文件大小 let metadata = metadata("test.txt").unwrap(); println!("File size: {} bytes", metadata.len()); }

三种方案的选择

这三种方案的选择要根据实际情况,通常第二个方案。但是如果真的字段太多要写的unwrap太多的话就需要考虑其他的方案。

如果代码足够简单,可以轻松检查代码的安全性,那么第三种ManuallyDrop方案也是非常好的。

相关新闻

  • JPMorgan、摩根士丹利案例可查,美国金融求职的专业内推如何运作? - Matthewmx
  • 若依项目Linux生产环境治理:文件系统权限配置实战
  • 2026.7.23:安装Windows下的mingw工具

最新新闻

  • 开源自动化运维平台Spug深度解析:从Docker部署到自动化发布的实战指南
  • 武汉12700家装修公司,为什么有人只靠老客户介绍就活了下来? - 品牌红黑榜
  • 内行人都在用的5个寄件省钱平台 - 快递物流实时资讯
  • 全屋定制工程化实践:板材选型、成本控制与质量验收的系统化总结
  • 寄快递怎么省钱?内行人5步攻略 - 快递物流实时资讯
  • 如何快速解密微信聊天记录:三步搞定本地数据恢复的终极指南

日新闻

  • 武汉卡地亚LOVE钻戒与钻石项链回收变现攻略|多家门店行情参考 - 大牌深度测评
  • 2026年无锡地区健康管理如何考量?四家机构业务体系概览
  • 2026图片去水印软件哪个好用 手机电脑免费工具盘点 - 免费软件工具方法教程

周新闻

  • SaaS软件行业GEO实践:AI搜索时代的品牌可见性与获客新路径
  • 什么是PCTFE?医药高端包装的“防潮王牌“材料
  • 【JVM调优实战】16-可视化利器-JConsole-VisualVM-JMC

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号