问题描述
我正在寻找一种方法,以确保结构寿命超过赋予该结构方法的参数.即使该结构在离开方法后不保留对该数据的引用.
I am looking for a way to ensure a struct outlives the parameter given to a method of that struct.Even if the struct doesn't hold a reference to that data after leaving the method.
这用于馈送给FFI的包装原始指针.我想保证实现FFI的结构的寿命超过了我用来将Rust对象馈送到指针包装程序的 Option<&'a Any>
.
This is for wrapped raw pointers fed to an FFI. I want to guarantee that the struct implementing the FFI outlives the Option<&'a Any>
I use to feed the Rust object to the pointer wrapper.
Context
是FFI包装器.数据
具有映射到FFI类型的不同类型.FFI函数会在返回之前立即复制所有这些类型.
Context
is the FFI wrapper.Data
holds different types that map to FFI types. The FFI functions copies all these types immediately before returning.
除了原始指针.
因此,我为这些代码在 Context
中添加了一个生存期说明符,并在 send_data()
中使用了该说明符.
So I add a lifetime specifier to Context
just for those and use that in send_data()
.
但是这还不够.我希望下面的代码无法编译.
But somehow this is not enough. I expected below code to not compile.
Rust Discord建议某人在 send_data()
中使& self
mut
可用.这具有理想的效果,但是我的FFI是线程安全的(并且是无状态的),并且 send_data()
是时间紧迫的.因此,我非常想避免这种情况.
someone one the Rust Discord suggested making &self
mut
able in send_data()
. This has the desired effect but my FFI is thread safe (and stateless) and send_data()
is time critical. So I would very much like to avoid this.
use std::any::Any;
use std::marker::PhantomData;
struct IntegerArray<'a> {
data: &'a [i32],
}
struct WrappedRawPointer<'a> {
ptr: *const std::ffi::c_void,
_marker: PhantomData<&'a ()>,
}
impl<'a> WrappedRawPointer<'a> {
fn new(data: Option<&'a dyn Any>) -> Self {
Self {
ptr: data
.map(|p| p as *const _ as *const std::ffi::c_void)
.unwrap_or(std::ptr::null()),
_marker: PhantomData,
}
}
}
enum Data<'a, 'b> {
IntegerArray(IntegerArray<'a>),
WrappedRawPointer(WrappedRawPointer<'b>),
}
struct Context<'a> {
ctx: u32,
_marker: PhantomData<&'a ()>,
}
impl<'a> Context<'a> {
fn new() -> Self {
Self {
ctx: 0, // Call FFI to initialize context
_marker: PhantomData,
}
}
fn send_data(&self, data: Data<'_, 'a>) {
match data {
Data::IntegerArray(_i) => (), // Call FFI function
Data::WrappedRawPointer(_p) => (), // Call FFI function
}
}
}
fn main() {
let ctx = Context::new();
{
let some_float: f32 = 42.0;
ctx.send_data(
Data::WrappedRawPointer(
WrappedRawPointer::new(
Some(&some_float)
)
)
);
// I would like rustc to complain
// here that some_float does not
// outlive ctx
}
// Explicitly drop outside
// the previous block to
// prevent rustc from being
// clever
drop(ctx);
}
推荐答案
使 send_data
接受& mut self
而不是& self
之所以起作用,是因为相对于 Self
类型,它使 self
参数不变的类型成为可能.子类型和差异在Rustonomicon中进行了描述,以及其他有关此处的问题堆栈溢出(请参见下文).
Making send_data
take &mut self
instead of &self
works because it makes the type of the self
parameter invariant with respect to the type Self
. Subtyping and Variance is described in the Rustonomicon, as well as other questions here on Stack Overflow (see below).
由于即使在 self
是不可变的引用时也要保持不变,因此这表明 Context<'a>
自身的方差是错误的:它在'a
中是协变的,但是应该是不变的.您可以通过将 PhantomData
的类型参数更改为在'a
中相同的东西来解决此问题:
Since you want invariance even when self
is an immutable reference, that suggests that the variance of Context<'a>
itself is wrong: it is covariant in 'a
, but it should be invariant. You can fix this by changing the type argument to PhantomData
to something that is also invariant in 'a
:
struct Context<'a> {
ctx: u32,
_marker: PhantomData<*mut &'a ()>, // or Cell<&'a ()>, or fn(&'a ()) -> &'a (), etc.
}
PhantomData
不仅仅是您机械地添加的内容,以使编译器不会对您大吼大叫. PhantomData
的类型参数的特定形式告诉编译器如何您的结构与其类型和生存期参数相关(当编译器无法自行解决时).在这种情况下,您想告诉编译器,即使 Context<'some_long_lifetime>
也不能代替 Context<'a_much_shorter_lifetime>
尽管它的所有字段都将允许该替换.
PhantomData
is not just something you add mechanically to make the compiler not yell at you. The specific form of the type argument to PhantomData
tells the compiler how your struct is related to its type and lifetime parameters (when the compiler can't figure it out by itself). In this case you want to tell the compiler that a Context<'some_long_lifetime>
can't be substituted for a Context<'a_much_shorter_lifetime>
even though its fields would all allow that substitution.
- 该实例看似如何无法使用自己的参数一生?
- 为什么链接生命周期仅对可变引用有意义?/a>
- 如何共享一个(如果
Context
应该是Send
或Sync
,则可能与线程中的幻像指针相关联)
- How can this instance seemingly outlive its own parameter lifetime?
- Why does linking lifetimes matter only with mutable references?
- How do I share a struct containing a phantom pointer among threads? (may be relevant if
Context
should beSend
orSync
)
这篇关于使结构的寿命超过提供给该结构的方法的参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!