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

标签 rust ffi lifetime

我正在尝试将 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

最佳答案

展开生命周期省略后, Parser::parse 的签名是

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

换句话说,就是:

Given a reference to a Parser and a reference to a str, maybe return a WootheeResult that contains one or more references to the Parser or some component of it.

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

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

  • parser 活得不够长”
  • “借入的值(value)必须在生命周期'a”内有效

我没有深入研究 woothee 的实现,但这个签名非常令人惊讶。我可以理解它是否返回对已解析字符串的引用,而不是对解析器 的引用。这尤其令人惊讶,因为该方法需要 &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% 的把握可以更改箱子以返回 'static来自 get_default_dataset 的字符串, 然后 parse会是

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

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

关于rust - 为 FFI 返回具有生命周期的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42564300/

相关文章:

haskell - 定义可存储实例时如何找到对齐值

c++ - 在自己的初始化器中使用变量

string - 如何复制 String 或 str

rust - 在向量中找到匹配的枚举,并在Rust中返回错误

testing - 所有测试完成后是否可以运行代码?

c++ - 从C++调用Rust时,如何通过引用传递参数?

c++ - 为 Ruby 使用 FFI 包装 C 函数

haskell - 哪些编译器支持 Haskell FFI

string - "Borrowed value does not live long enough", 在循环中使用时丢弃

rust - 如何在 Rust Cargo.toml 中执行基准测试