在Rust中,临时指针是否可以是原始指针?

12

我有一个像这样的函数:

extern {
    fn foo(layout: *const RawLayout) -> libc::uint8_t;
}

fn bar(layout: Layout) -> bool {
    unsafe {
        foo(&layout.into() as *const _) != 0
    }
}

Layout是一种可复制类型,可以转换为RawLayout使用.into()

我想确保我理解了这个不安全的操作。据我理解,layout.into()创建一个临时的RawLayout,然后&获取对它的引用,并且as *const _将其转换为原始指针(*const RawLayout)。然后调用foo()函数并返回,最后临时的RawLayout被丢弃。

是这样吗?还是有一些棘手的原因我不应该这样做?


3
我不知道答案,但我认为我会硬着头皮添加一个明确的变量,即使只是为了尽可能地使代码易于理解。unsafe 本来就需要足够的脑力。 - Shepmaster
1个回答

4
你是对的。在这种情况下,首先调用foo,然后丢弃RawLayout。这在Rust参考文档中有解释(请点击链接查看具体示例):

临时值的生命周期通常是最内层的封闭语句

然而,我更倾向于遵循Shepmaster的建议。明确引入一个局部变量可以帮助代码读者集中精力处理更重要的事情,比如确保不安全的代码正确无误(而不是必须理解临时变量的确切语义)。

如何检查这个问题

您可以使用以下代码来检查此行为:
struct Layout;
struct RawLayout;

impl Into<RawLayout> for Layout {
    fn into(self) -> RawLayout {
        RawLayout
    }
}

impl Drop for RawLayout {
    fn drop(&mut self) {
        println!("Dropping RawLayout");
    }
}

unsafe fn foo(layout: *const RawLayout) -> u8 {
    println!("foo called");
    1
}

fn bar(layout: Layout) -> bool {
    unsafe {
        foo(&layout.into() as *const _) != 0
    }
}

fn main() {
    bar(Layout);    
}

输出结果为:
foo called
Dropping RawLayout

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接