将生存期约束添加到非引用类型 [英] Adding lifetime constraints to non-reference types

查看:95
本文介绍了将生存期约束添加到非引用类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图弄清楚如何应用Rust生存期来向Erlang NIF模块添加一些编译时强制. NIF模块是通常使用C语言编写的可提供扩展的共享库.

I am trying to figure out how to apply Rust lifetimes to add some compile-time enforcement to Erlang NIF modules. NIF modules are shared libraries normally written in C that provide extensions.

您将在C语言中编写的回调的简化原型如下:

A simplified prototype of the callback you would write in C looks like this:

Handle my_nif_function(Heap *heap, Handle handle);

为您提供了一个句柄和一个指向拥有它的堆的指针.在回调中,您可以检查输入句柄,在堆上创建更多句柄,并在函数返回时返回其中之一.回调返回后,堆及其所有句柄都将变为无效,因此您不得在回调期间存储堆或其句柄的副本.不幸的是,我看到人们确实做到了这一点,最终导致神秘的模拟器崩溃. Rust可以强制执行这些生命周期限制吗?

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?

认为可以通过将其转换为引用来轻松管理堆.

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?

另一个麻烦之处在于,您还可以创建自己的堆和句柄,使它们 处于回调调用范围之外.在C ++中,我将std::unique_ptr与自定义析构函数一起使用.什么是Rust等效项?用于管理堆的[简化的] C API看起来像这样:

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. What is the Rust equivalent? The [simplified] C API for managing heaps looks like this:

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

参考:此处描述了NIF: http://www.erlang.org/doc /man/erl_nif.html . 堆"和句柄"的Erlang名称是环境"和术语".我使用了堆"和句柄"这两个名称,以便可以更广泛地理解这个问题.

Reference: NIFs are described here: http://www.erlang.org/doc/man/erl_nif.html . The Erlang names for "heaps" and "handles" are "environments" and "terms". I used the names "heaps" and "handles" so that the question would be more broadly understood.

推荐答案

Rust 1.0

各种标记类型已被统一为一种: PhantomData

The various marker types have been unified into one: 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
    };
}

原始答案

以下是使用 ContravariantLifetime 的示例.我们将原始堆指针包装到一个结构中,然后将原始句柄指针包装在另一个结构中,以重用堆的生命周期.

Here's an example of using 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
    };
}

生命周期标记

有3个生命周期标记.在这里,我不会尝试复制相当不错但密集的文档,但也可以指出密集的 Wikipedia 页面,这可能会有些帮助.我按照您最有可能使用它们的顺序列出了它们:

Lifetime markers

There are 3 lifetime markers. 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. I've listed them in the order that you are most likely to use them:

这篇关于将生存期约束添加到非引用类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆