Rust 如何安全地使用由唯一ID表示的外部数据?
我可能希望在Rust中与许多外部系统(网络API、FFI到遗留C库等)进行交互,它们使用数字ID表示远程资源。这些ID通常有一个隐含的上下文,在该上下文中它们是有效的,并且在程序持有它们时可能会过期 我习惯于在其他编程语言中处理这个问题,但是在阅读了Rust书籍(特别是在讨论字符串索引的地方)之后,我觉得避免在我的程序中直接公开这些ID会更清晰、更安全,因为它们依赖于上下文,并且不能保证它们在将来是有效的Rust中是否存在允许我安全地与ID表示的远程资源交互的模式? 考虑一个我尝试使用的特定ABI的简化示例,该示例演示了这个问题:Rust 如何安全地使用由唯一ID表示的外部数据?,rust,Rust,我可能希望在Rust中与许多外部系统(网络API、FFI到遗留C库等)进行交互,它们使用数字ID表示远程资源。这些ID通常有一个隐含的上下文,在该上下文中它们是有效的,并且在程序持有它们时可能会过期 我习惯于在其他编程语言中处理这个问题,但是在阅读了Rust书籍(特别是在讨论字符串索引的地方)之后,我觉得避免在我的程序中直接公开这些ID会更清晰、更安全,因为它们依赖于上下文,并且不能保证它们在将来是有效的Rust中是否存在允许我安全地与ID表示的远程资源交互的模式? 考虑一个我尝试使用的特定AB
// Windows are represented as a unique ID per connection.
type WindowId = u64;
/// Fetches a list of Windows from the display server.
fn get_windows() -> Vec<WindowId> {
// Makes an external call to display server to get a list of Window IDs.
...
}
/// Wait for the next event sent by the display server.
fn get_event() -> Event {
// Blocks until we receive an event, one of which can indicate that a
// Window has been destroyed and is no longer valid.
...
}
/// Example of a function that uses a Window to fetch data.
fn get_window_dimensions(window: WindowId) -> (u32, u32) {
// Makes an extermal call to display server to ask for the dimensions of
// the window referenced by the provided WindowId.
...
}
/// Example of a function that uses a Window to modify data.
fn set_window_dimensions(window: WindowId, x: u32, y:u32) {
// Makes an extermal call to display server to set the dimensions for
// the window referenced by the provided WindowId.
...
}
//窗口表示为每个连接的唯一ID。
类型WindowId=u64;
///从显示服务器获取窗口列表。
fn get_windows()->Vec{
//对display server进行外部调用以获取窗口ID列表。
...
}
///等待显示服务器发送的下一个事件。
fn get_event()->event{
//块,直到我们收到一个事件,其中一个事件可以指示
//窗口已被销毁,不再有效。
...
}
///使用窗口获取数据的函数示例。
fn获取窗口尺寸(窗口:WindowId)->(u32,u32){
//对display server进行外部调用,以询问
//由提供的WindowId引用的窗口。
...
}
///使用窗口修改数据的函数示例。
fn设置窗口尺寸(窗口:窗口ID,x:u32,y:u32){
//对display server进行外部调用以设置的维度
//由提供的WindowId引用的窗口。
...
}
此代码要求我们使用WindowId
s引用窗口资源,但值得注意的是,如果:
destroy\u Window()
函数来破坏窗口WindowId
s无效WindowId
时,如果不使用某种方法将作用域显式编码到其中,就会感到脆弱。例如,存储WindowId
的程序的其他部分可能会突然发现引用的相关窗口无效,并且可能需要检测和处理这种情况
这感觉可能会很快变得一团糟!在这些约束条件下,我是否可以安全地与生锈的窗口进行交互,或者我是否需要直接处理
WindowId
s?根据您的描述,结构可能适合这里,因为用户似乎从不需要id的实际数值
struct WindowId(u64);
这并不能解决ID失效的问题。
要解决第1点,您可以使导致Id无效的函数使用该Id(按值获取),前提是上述新类型结构没有派生副本,并且如果合理,也没有实现克隆
impl WindowId{
fn(自我毁灭){
/*…剪断*/
}
}
这仍然保留第2点和第3点,最好的选择可能是所有通过其ID访问窗口的操作都是可失败的,例如通过返回
impl WindowId{
fn大小(自身)->结果{
/*…剪断*/
}
}
为什么不创建一个结构窗口{id:u64}
并向其中添加方法?至于无效,在客户端上下文中,当窗口ID变为无效时,所需的行为到底是什么?在某些上下文中(如处理其他事件时),窗口将被视为有效,但一般来说,如果窗口ID变为无效,则应丢弃对它的任何引用。@malwrar您提到的“隐含上下文”,对于窗口
s,您的案例中是否有一个?如果是这样的话,就有可能简化Skgland的答案,只使用一个初始方法返回结果
。我还不清楚这一点,比如说客户端有一个窗口
或窗口ID
结构。一旦窗口失效,如果客户端尝试使用该结构会发生什么?当您说“应该丢弃它”时,当窗口ID无效时,当前正在调用某个窗口API的代码会发生什么情况?另外,客户端如何通过轮询“发现”失效?我担心我需要让每个方法都返回一个结果,但我认为这可能是解决方案。在接受这个答案之前,我会先把它打开一点。