Tôi đã tạo một trình bao bọc quanh thư viện C tạo thiết bị mà bạn phải đóng một cách rõ ràng.Cách quấn thư viện gốc với ngữ nghĩa init/exit
Việc viết các hàm FFI thô dễ dàng, nhưng làm cách nào để làm cho nó hoạt động hiệu quả trong một trình bao bọc cấp cao hơn?
Cụ thể, tôi có nên sử dụng kiểu RAII và chỉ sử dụng Drop
để đảm bảo đóng được gọi khi nó nằm ngoài phạm vi, thay vì hiển thị phương thức close()
cho người gọi? Cách nào là thành ngữ nhất trong Rust?
Về cơ bản có 3 lựa chọn:
- wrapper mỏng đòi hỏi cùng
close()
cuộc gọi như thư viện C; - Kiểu RAII không bị lộ
close()
, chỉ thực hiệnDrop
; - C#
dispose()
cách triển khai theo dõi trạng thái đã đóng và cho phép cả hai hình thức đóng.
Hình thức cuối cùng trông như thế này:
pub enum NativeDevice {} // Opaque pointer to C struct
fn ffi_open_native_device() -> *mut NativeDevice { unimplemented!() }
fn ffi_close_native_device(_: *mut NativeDevice) {}
fn ffi_foo(_: *mut NativeDevice, _: u32) -> u32 { unimplemented!() }
pub struct Device {
native_device: *mut NativeDevice,
closed: bool,
}
impl Device {
pub fn new() -> Device {
Device {
native_device: ffi_open_native_device(),
closed: false,
}
}
pub fn foo(&self, arg: u32) -> u32 {
ffi_foo(self.native_device, arg)
}
pub fn close(&mut self) {
if !self.closed {
ffi_close_native_device(self.native_device);
self.closed = true;
}
}
}
impl Drop for Device {
fn drop(&mut self) {
self.close();
}
}
Lựa chọn số 2. Tôi không bao giờ thấy tùy chọn 1 hoặc 3 được sử dụng trong gỉ. Trong ví dụ của bạn, điều gì sẽ xảy ra khi 'close' được gọi nhiều lần? – malbarbo
Cũng được phát hiện, dĩ nhiên, nếu đóng cửa, bạn nên dùng phương thức close() chứ không phải trong drop(). Đã chỉnh sửa. –