为 FFI 返回具有生命周期的结构

ian*_*nks 2 ffi lifetime rust

我正在尝试将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()
}
Run Code Online (Sandbox Code Playgroud)

这是我得到的错误:

#![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()
}
Run Code Online (Sandbox Code Playgroud)

She*_*ter 5

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

fn parse<'a, 'b>(&'a self, agent: &'b str) -> Option<WootheeResult<'a>>
Run Code Online (Sandbox Code Playgroud)

一句话,就是:

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

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

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

  • parser活得不够久”
  • “借来的价值必须在生命周期‘a’内有效”

我还没有深入研究 woothee 的实现,但是这个签名非常令人惊讶。我可以理解它是否返回了对已解析字符串的引用,而不是对parser 的引用。这尤其令人惊讶,因为该方法需要&self基于解析来修改内部结构,那么为什么它会返回对自身的引用呢?

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

pub fn get_default_dataset<'a>() -> HashMap<&'a str, WootheeResult<'a>>
Run Code Online (Sandbox Code Playgroud)

是否有任何方法可以返回对在函数中创建的变量的引用?,除非该局部变量是 ,否则您不能返回对局部变量的引用'static。需要注意的是,我还没有尝试过,我 80% 肯定可以将板条箱更改为'static从返回字符串get_default_dataset,然后parse将是

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

并且WootheeResult将是WootheeResult<'static>,然后事情就会“正常工作”。