【问题标题】:Return struct with lifetime for FFI为 FFI 返回具有生命周期的结构
【发布时间】:2017-03-02 19:29:53
【问题描述】:

我正在尝试将 woothee-rust 板条箱中的函数公开给 Ruby。为此,我正在解析输入字符串并尝试将结果作为 C 结构返回。我遇到了解析器的生命周期“活得不够长”的问题。我不确定为什么解析器的生命周期必须超过函数。

#![feature(libc)]
#![feature(cstr_to_str)]
#![feature(cstr_memory)]
extern crate libc;
extern crate woothee;

use woothee::parser::{Parser,WootheeResult};
use std::ffi::{CStr,CString};

#[no_mangle]
pub extern fn parse<'a>(ua_string: *const libc::c_char) -> WootheeResult<'a> {
    let input = unsafe { CStr::from_ptr(ua_string) };
    let parser = Parser::new();
    parser.parse(input.to_str().unwrap()).unwrap()
}

这是我得到的错误:

error: `parser` does not live long enough
  --> src/lib.rs:14:5
   |
14 |     parser.parse(input.to_str().unwrap()).unwrap()
   |     ^^^^^^ does not live long enough
15 | }
   | - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the body at 11:77...
  --> src/lib.rs:11:78
   |
11 |   pub extern fn parse<'a>(ua_string: *const libc::c_char) -> WootheeResult<'a> {
   |  ______________________________________________________________________________^ starting here...
12 | |     let input = unsafe { CStr::from_ptr(ua_string) };
13 | |     let parser = Parser::new();
14 | |     parser.parse(input.to_str().unwrap()).unwrap()
15 | | }
   | |_^ ...ending here

【问题讨论】:

    标签: rust ffi lifetime


    【解决方案1】:

    扩展生命周期省略后,Parser::parse 的签名为

    fn parse<'a, 'b>(&'a self, agent: &'b str) -> Option<WootheeResult<'a>>
    

    换句话说,就是:

    给定对Parser 的引用和对str 的引用,可能会返回一个WootheeResult,其中包含对Parser 或其某些组件的一个或多个引用。

    但是,当函数退出时,您会立即销毁 Parser。所以,不,你不能这样做,因为这样做会允许访问对未定义内存的引用。 Rust 已阻止您在程序中引入安全漏洞。

    回到错误信息,希望现在更有意义:

    • parser 的寿命不够长”
    • "借来的值必须在生命周期内有效'a"

    我还没有深入研究 woothee 的实现,但是这个签名非常令人惊讶。我可以理解它是否返回对已解析字符串的引用,而不是对 parser 的引用。这尤其令人惊讶,因为该方法采用 &amp;self — 它不太可能根据解析修改内部,那么为什么它会返回对自身的引用?

    查看Parser::new的实现,生命周期似乎是从dataset::get_default_dataset驱动的:

    pub fn get_default_dataset<'a>() -> HashMap<&'a str, WootheeResult<'a>>
    

    Is there any way to return a reference to a variable created in a function? 中所述,您不能返回对局部变量的引用,除非该局部变量是'static。需要注意的是,我没有尝试过这个,我有 80% 的把握可以将 crate 更改为从 get_default_dataset 返回 'static 字符串,然后 parse 将是

    impl<'a> Parser<'a> {
        fn parse<'b>(&'b self, agent: &'b str) -> Option<WootheeResult<'a>>
    }
    

    WootheeResult 将是WootheeResult&lt;'static&gt;,然后事情就会“正常工作”。

    【讨论】:

    • 好的,这个错误现在有意义了。但是,我不知道如何使解析器超过函数的生命周期。这样做的最佳做法是什么?
    • @ianks 确保解析器寿命比函数调用长的唯一解决方案是在函数外部创建解析器,然后传入引用。通过构造,解析器的寿命将比函数长。
    • 还有另一种选择;返回解析器以及WootheeResult。一种方法是使用owning_ref,它允许您返回一个对象,该对象的行为类似于WootheeResult,但包含一个拥有的解析器。
    • @ChrisEmerson 说得好,但由于这是一个 extern 函数,我认为返回复杂的结构并不合适。此外,该函数不能改变任何对owning_ref有效的东西,在这种情况下是正确的,但没有意义......
    猜你喜欢
    • 2019-08-05
    • 2016-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多