【问题标题】:How can I enforce lifetimes for a struct that contains a raw pointer?如何为包含原始指针的结构强制执行生命周期?
【发布时间】:2015-01-14 09:18:32
【问题描述】:

编者注:此代码不再在 Rust 1.0 中编译,错误为 parameter `'a` is never used。这个错误的原因正是因为下面演示的问题,所以(更新的)解决方案仍然适用。

extern crate core;
use core::ops::{Deref, DerefMut};

struct MutPtr<'a, T> {
    ptr: *mut T,
}
impl<'a, T> MutPtr<'a, T> {
    fn new<'b>(value: &'b mut T) -> MutPtr<'b, T> {
        MutPtr { ptr: value }
    }
}
impl<'a, T> Deref for MutPtr<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &(*self.ptr) }
    }
}
impl<'a, T> DerefMut for MutPtr<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut (*self.ptr) }
    }
}
struct Bar {
    v: i32,
}

fn err<'a>() -> MutPtr<'a, Bar> {
    let mut b = Bar { v: 42 };
    MutPtr::new(&mut b) // Shouldn't this throw an error?
}

fn main() {
    let mut b = Bar { v: 42 };
    let mut ptr_b = MutPtr::new(&mut b);
    let mut ptr_b1 = MutPtr::new(&mut b);

    ptr_b.v = 10;
    println!("{}", b.v);
    ptr_b1.v = 21;
    println!("{}", b.v);
}

这个代码块引起了一些混乱:

fn err<'a>() -> MutPtr<'a, Bar> {
    let mut b = Bar { v: 42 };
    MutPtr::new(&mut b) // Shouldn't this throw an error?
}

为什么会编译?

当我打电话时

MutPtr::new(&mut b)

它不应该有b 的生命周期吗?我预计会出现编译错误,因为生命周期 'aMutPtr&lt;'b, Bar&gt; 的生命周期长。

【问题讨论】:

  • 您是否有意将值存储为*mut T 而不是&amp;'a mut T
  • @Dogbert 是的,因为我想要在同一个范围内有多个可变指针。(仅用于实验)

标签: rust lifetime borrow-checker


【解决方案1】:

我认为您正在寻找的是core::marker::PhantomData(也可以在std::marker::PhantomData 中找到)。 发生的情况是编译器没有为指针变量分配任何生命周期,因此编译器不知道如何约束结构的生命周期。

这样做的方法是在你的结构中添加一个标记PhantomData&lt;&amp;'a ()&gt;,它告诉编译器整个结构的生命周期可能不会超过'a(实际上,假设MutPtr&lt;'a, T&gt;有一个&amp;'a ()字段,即使它没有)。

所以最后你的结构应该是这样的:

struct MutPtr<'a, T> {
    ptr: *mut T,
    _covariant: PhantomData<&'a ()>,
}

impl<'a, T> MutPtr<'a, T> {
    fn new(value: &'a mut T) -> MutPtr<'a, T> {
        MutPtr {
            ptr: value,
            _covariant: PhantomData,
        }
    }
}

这样你会得到预期的错误b does not live long enough

【讨论】:

  • 几分钟前我也做过同样的事情。问题在于,一旦我完成了MutPtr::new(&amp;mut b)b.v 将不再工作。我假设ContravariantLifetime 保存变量是可变借用的?错误是cannot use b.v because it was mutably borrowed
  • 我猜这个问题是因为你试图做的(创建两个对相同内容的可变引用)被明确标记为undefined behaviour。因此,您可能无法提供实现这种行为的安全接口,或者至少我不知道。
  • @MaikKlein:您应该看看RefCell,例如,它可以让您拥有许多对RefCell 的不可变引用,您可以从中获得对内部的可变引用,如只要一次只有一个活动的可变借用。
  • 我想试试ContravariantLifetime?我在哪里可以找到它?我是否需要在启用功能的情况下使用不稳定的生锈?我需要使用图书馆吗? use std::marker::ContravariantLifetime; no ContravariantLifetime` 在marker 中出现错误。
  • ContravariantLifetime 前段时间被std::marker::PhantomData 取代。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-25
  • 1970-01-01
  • 1970-01-01
  • 2015-03-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多