简体   繁体   English

将生存期约束添加到非引用类型

[英]Adding lifetime constraints to non-reference types

I am trying to figure out how to apply Rust lifetimes to add some compile-time enforcement to Erlang NIF modules. 我试图弄清楚如何应用Rust生存期来向Erlang NIF模块添加一些编译时强制。 NIF modules are shared libraries normally written in C that provide extensions. NIF模块是通常使用C语言编写的提供扩展的共享库。

A simplified prototype of the callback you would write in C looks like this: 您将在C中编写的回调的简化原型如下所示:

Handle my_nif_function(Heap *heap, Handle handle);

You are provided a handle and a pointer to the heap that owns it. 提供了一个句柄和一个指向拥有它的堆的指针。 In your callback you may inspect the input handle, create more handles on the heap, and return one of them as the function return. 在回调中,您可以检查输入句柄,在堆上创建更多句柄,并在函数返回时返回其中之一。 The heap and all its handles become invalid after your callback returns, so you must not store copies of the heap or its handles during the callback. 回调返回后,堆及其所有句柄将变为无效,因此您不得在回调期间存储堆或其句柄的副本。 Unfortunately I've seen people do exactly this and it eventually results in a mysterious emulator crash. 不幸的是,我见过人们确实做到了这一点,最终导致神秘的模拟器崩溃。 Can Rust enforce these lifetime constraints? Rust可以强制执行这些生命周期约束吗?

I think the heap can be easily managed by turning it into a reference. 认为可以通过将其转换为引用来轻松管理堆。

fn my_nif_function(heap: &Heap, handle: Handle) -> Handle

But how can I link the lifetime of the input and output handles to the heap? 但是,如何将输入和输出句柄的生存期链接到堆?

Another wrinkle to this is that you can also create your own heaps and handles which are allowed to live outside the scope of a callback invocation. 另一个麻烦是,您还可以创建自己的堆和句柄, 这些堆和句柄可以驻留在回调调用范围之外。 In C++ I would use std::unique_ptr with a custom destructor. 在C ++中,我将std::unique_ptr与自定义析构函数结合使用。 What is the Rust equivalent? 什么是Rust等效项? The [simplified] C API for managing heaps looks like this: 用于管理堆的[简化] C API如下所示:

Heap *create_heap();
void destroy_heap(Heap *);

Reference: NIFs are described here: http://www.erlang.org/doc/man/erl_nif.html . 参考:此处描述了NIF: http ://www.erlang.org/doc/man/erl_nif.html。 The Erlang names for "heaps" and "handles" are "environments" and "terms". “堆”和“句柄”的Erlang名称是“环境”和“术语”。 I used the names "heaps" and "handles" so that the question would be more broadly understood. 我使用了“堆”和“句柄”这两个名称,以便更广泛地理解该问题。

Rust 1.0 锈1.0

The various marker types have been unified into one: PhantomData 各种标记类型已统一为一种: PhantomData

use std::ptr;
use std::marker::PhantomData;

struct Heap {
    ptr: *const u8,
}

impl Heap {
    fn new(c_ptr: *const u8) -> Heap {
        Heap {
            ptr: c_ptr
        }
    }

    fn wrap_handle<'a>(&'a self, c_handle: *const u8) -> Handle<'a> {
        Handle {
            ptr: c_handle,
            marker: PhantomData,
        }
    }
}

struct Handle<'a> {
    ptr: *const u8,
    marker: PhantomData<&'a ()>, 
}

fn main() {
    let longer_heap = Heap::new(ptr::null());

    let handle = {
        let shorter_heap = Heap::new(ptr::null());

        let longer_handle = longer_heap.wrap_handle(ptr::null());
        let shorter_handle = shorter_heap.wrap_handle(ptr::null());

        // longer_handle // ok to return
        // shorter_handle // error: `shorter_heap` does not live long enough
    };
}

Original Answer 原始答案

Here's an example of using ContravariantLifetime . 这是使用ContravariantLifetime的示例。 We wrap the raw heap pointer into a struct and then wrap raw handle pointers in another struct, reusing the lifetime of the heap. 我们将原始堆指针包装到一个结构中,然后将原始句柄指针包装在另一个结构中,以重用堆的生存期。

use std::ptr;
use std::marker::ContravariantLifetime;

struct Heap {
    ptr: *const u8,
}

impl Heap {
    fn new(c_ptr: *const u8) -> Heap {
        Heap {
            ptr: c_ptr
        }
    }

    fn wrap_handle<'a>(&'a self, c_handle: *const u8) -> Handle<'a> {
        Handle {
            ptr: c_handle,
            marker: ContravariantLifetime,
        }
    }
}

struct Handle<'a> {
    ptr: *const u8,
    marker: ContravariantLifetime<'a>,
}

fn main() {
    let longer_heap = Heap::new(ptr::null());

    let handle = {
        let shorter_heap = Heap::new(ptr::null());

        let longer_handle = longer_heap.wrap_handle(ptr::null());
        let shorter_handle = shorter_heap.wrap_handle(ptr::null());

        // longer_handle // ok to return
        // shorter_handle // error: `shorter_heap` does not live long enough
    };
}

Lifetime markers 终身标记

There are 3 lifetime markers. 有3个生命周期标记。 I won't attempt to replicate the reasonably good but dense documentation here, but can also point out the dense Wikipedia page, which might be some small assistance. 在这里,我不会尝试复制相当不错但密集的文档,但也可以指出密集的Wikipedia页面,这可能会有些帮助。 I've listed them in the order that you are most likely to use them: 我按照您最有可能使用它们的顺序列出了它们:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM