当涉及原始指针时,Rust 如何推断生命周期?

发布于 2025-01-10 08:33:35 字数 992 浏览 0 评论 0原文

struct MyCell<T> {
    value: T
}

impl<T> MyCell<T> {
    fn new(value: T) -> Self {
        MyCell { value }
    }
    
    fn get(&self) -> &T {
        &self.value
    }
    
    fn set(&self, new_value: T) {
        unsafe { 
            *(&self.value as *const T as *mut T) = new_value; 
        }
    }
}

fn set_to_local(cell: &MyCell<&i32>) {
    let local = 100;
    cell.set(&local);
}

fn main() {
    let cell = MyCell::new(&10);
    set_to_local(&cell);
}

当调用cell.set(&local)时,假设cell'x'&local'y,我被告知协方差规则会将 cell 的类型从 &MyCell<'x, &i32> 更改为&MyCell<'y, &i32>

unsafe 块内的赋值如何影响 set() 参数的生命周期推断?原始指针没有生命周期,那么编译器如何知道它应该使用协方差使 cellnew_value 具有相同的生命周期?

struct MyCell<T> {
    value: T
}

impl<T> MyCell<T> {
    fn new(value: T) -> Self {
        MyCell { value }
    }
    
    fn get(&self) -> &T {
        &self.value
    }
    
    fn set(&self, new_value: T) {
        unsafe { 
            *(&self.value as *const T as *mut T) = new_value; 
        }
    }
}

fn set_to_local(cell: &MyCell<&i32>) {
    let local = 100;
    cell.set(&local);
}

fn main() {
    let cell = MyCell::new(&10);
    set_to_local(&cell);
}

When calling cell.set(&local), suppose cell is 'x and '&local is 'y, I am told that the covariance rule will change the type of cell from &MyCell<'x, &i32> to &MyCell<'y, &i32>.

How does the assignment inside the unsafe block affect the lifetime inference for the parameters of set()? Raw pointers does not have lifetime then how does the compiler know it should make cell and new_value have the same lifetime using covariance?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小猫一只 2025-01-17 08:33:35

不安全块内的赋值如何影响 set() 参数的生命周期推断?

事实并非如此——这甚至不是特定于原始指针或不安全。函数体永远不会影响函数签名的任何方面(除了这里不相关的async fn)。

原始指针没有生命周期,那么编译器如何知道它应该使用协方差使 cellnew_value 具有相同的生命周期?

听起来你误读了一些建议。在您的代码中,CellT 中是不变的,但要使内部可变类型健全,它必须是不变 (非协变)在类型参数中。在您的代码中,编译器会推断 T 的协方差,因为 MyCell 包含一个简单类型 T 的字段。协方差是大多数泛型类型的“典型”情况。

因此,您的代码不健全,因为 MyCellT 上是协变的,但必须在 T 上保持不变。

您的代码不健全,因为在set()的实现中,您正在创建对T&的不可变引用;self.value,然后写入其所指对象。无论您如何执行,这都是“未定义行为”,因为创建 &self.value 向编译器/优化器断言指向的内存不会被修改直到引用被删除。

如果你想重新实现标准库的 Cell,你必须像标准库那样做,使用 UnsafeCell 原语:

pub struct Cell<T: ?Sized> {
    value: UnsafeCell<T>,
}

UnsafeCell 是您选择退出 & 的不变性保证的方式:创建一个 &UnsafeCell< /code> doesn't 断言 T 不会发生突变。它在 T 中也是不变的,这会自动使包含类型在 T 中不变。在这里,这两者都是必要的。

How does the assignment inside the unsafe block affect the lifetime inference for the parameters of set()?

It doesn't — and this is not even specific to raw pointers or unsafe. Function bodies never affect any aspect of the function signature (except for async fns which are irrelevant here).

Raw pointers does not have lifetime then how does the compiler know it should make cell and new_value have the same lifetime using covariance?

It sounds like you misread some advice. In the code you have, Cell<T> is invariant in T, but for an interior-mutable type to be sound, it must be invariant (not covariant) in the type parameter. In the code you have, the compiler infers covariance for T because MyCell contains a field that is simply of the type T. Covariance is the “typical” case for most generic types.

Therefore, the code you have is unsound because MyCell is covariant over T but must instead be invariant over T.

Your code is also unsound because in the implementation of set(), you're creating an immutable reference to a T, &self.value, and then writing to its referent. This is “undefined behavior” no matter how you do it, because creating &self.value asserts to the compiler/optimizer that the pointed-to memory won't be modified until the reference is dropped.

If you want to reimplement the standard library's Cell, you must do it like the standard library does, with the UnsafeCell primitive:

pub struct Cell<T: ?Sized> {
    value: UnsafeCell<T>,
}

UnsafeCell is how you opt out of &'s immutability guarantees: creating an &UnsafeCell<T> doesn't assert that the T won't be mutated. It is also invariant in T, which automatically makes the containing type invariant in T. Both of these are necessary here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文