rust 要理解“”参数,需要为“static”借用“variable”

m3eecexj  于 2023-04-06  发布在  其他
关注(0)|答案(1)|浏览(151)

我是一个全新的生 rust ,但有经验的C和我有这个生 rust 的代码不编译。

use std::fs;

static mut GRAPH_BUILDER: Option<Box<[&[u8]; 2]>> = None;

#[export_name = "wizer.initialize"]
pub extern "C" fn init() {
    let weights = fs::read("./mobilenet.bin").unwrap();
    let xml = fs::read_to_string("./mobilenet.xml").unwrap().into_bytes();
    let input: [&[u8]; 2] = [&weights, &xml];

    unsafe {
        GRAPH_BUILDER = Some(Box::new(input));
    }
}

pub fn main() {
    unsafe {
        if GRAPH_BUILDER.is_none() {
            init();
        }
    }
}

使用rustc main.rs编译时,会产生以下错误

error[E0597]: `weights` does not live long enough
  --> main.rs:9:30
   |
9  |     let input: [&[u8]; 2] = [&weights, &xml];
   |                              ^^^^^^^^ borrowed value does not live long enough
...
12 |         GRAPH_BUILDER = Some(Box::new(input));
   |                              --------------- argument requires that `weights` is borrowed for `'static`
13 |     }
14 | }
   | - `weights` dropped here while still borrowed

error[E0597]: `xml` does not live long enough
  --> main.rs:9:40
   |
9  |     let input: [&[u8]; 2] = [&weights, &xml];
   |                                        ^^^^ borrowed value does not live long enough
...
12 |         GRAPH_BUILDER = Some(Box::new(input));
   |                              --------------- argument requires that `xml` is borrowed for `'static`
13 |     }
14 | }
   | - `xml` dropped here while still borrowed

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0597`.

我理解这个错误是因为weights存储在堆栈上,当init函数终止时,它将被取消分配,所以静态GRAPH_BUILDER将包含一个指向未分配内存的指针。所以我尝试使用Box来代替,从我的理解应该像C中的malloc一样。但它似乎不起作用。我如何让rust在堆上分配weightsxml变量,而不知道它们在编译时的大小?即,malloc的rust等价物是什么?
我读过here,你可以调用clone来解决这个问题。但我不想这样做,因为我读入的文件很大。而且我也不明白为什么这会解决这个问题。克隆不会也在堆栈上结束吗?

EDIT:还有一件重要的事情需要提一下,我需要给wasi_nn::load函数提供一个参数GRAPH_BUILDER,它本质上期望它的数据类型是slice &[&[u8]]。但是我完全不知道如何将它转换成这个数据类型。下面是main函数的延续。

use wasi_nn;

pub extern "C" fn main() {
    bench::start();
    let context: wasi_nn::GraphExecutionContext;
    unsafe {
        if GRAPH_BUILDER.is_none() {
            init();
        }
    }

    let graph = unsafe {
        wasi_nn::load(
            &GRAPH_BUILDER.expect("Graph builder was not initialized"),
            wasi_nn::GRAPH_ENCODING_OPENVINO,
            wasi_nn::EXECUTION_TARGET_CPU,
        )
        .unwrap()
    };

我试图修改这段代码,使其在初始化函数中创建&[&xml.into_bytes(), &weights],而不是直接传递它。

sqxo8psd

sqxo8psd1#

malloc的rust等价物是什么?
这是一个完全不必要的问题,你不需要进一步挖掘,你需要真正看看你的代码,想想发生了什么。
Rust的&T不是一个C风格的野生指针,它是一个字典范围的借用智能指针。它只能引用在其整个生命周期内 * 字典 * 有效的数据。
所以我尝试使用Box来代替,从我的理解来看,它应该像C中的malloc一样。
当然不是,因为在你的盒子里,你仍然在放 * 对函数本地数据的引用 *。这正是Rust所抱怨的。
你并没有将数据复制或移动到堆中,你只是为同一个问题添加了一个间接地址:当函数结束时,weightsxml仍然会被删除,而你放在Box中的引用仍然会悬空,这是Rust不允许的。
但是weightsxmlVec<u8>,所以它们已经是拥有的,堆分配的数据类型。你所需要做的就是将它们移动到你的东西中:

static mut GRAPH_BUILDER: Option<(Vec<u8>, Vec<u8>)> = None;

[...]

        GRAPH_BUILDER = Some((weights, xml));

同样,你想在extern C函数中执行unwrap的次数甚至比在Rust函数中更少。据我所知,最好的情况下,这将立即中止,最坏的情况下,它是UB。

相关问题