英文:
Understanding "argument requires that `variable` is borrowed for `'static`"
问题
以下是您提供的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();
}
}
}
这段代码存在两个主要问题:
-
错误E0597:
weights
和xml
的生命周期问题。这是因为input
数组中包含对weights
和xml
的引用,但它们是在init
函数中创建的,该函数结束后它们的生命周期结束。为了解决这个问题,您可以使用Vec
来动态分配内存,然后将数据复制到堆上,以确保它们在GRAPH_BUILDER
中存在于整个程序生命周期中。请注意,这可能会导致更多的内存分配,但这是一种方式来解决生命周期问题。 -
数据类型问题:
GRAPH_BUILDER
被声明为Option<Box<[&[u8]; 2]>>
,但您提到需要将其转换为&[&[u8]]
。要做到这一点,您需要修改数据结构以适应需要的类型。以下是修改后的代码:
use std::fs;
static mut GRAPH_BUILDER: Option<Vec<Vec<u8>>> = 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: Vec<Vec<u8>> = vec![weights, xml];
unsafe {
GRAPH_BUILDER = Some(input);
}
}
pub fn main() {
unsafe {
if GRAPH_BUILDER.is_none() {
init();
}
}
}
这将使用Vec
来存储weights
和xml
,并将它们包装在GRAPH_BUILDER
中以满足所需的数据类型。这应该能够解决生命周期问题和数据类型问题。
英文:
I am completely new to rust but have prior experience in C and I have this rust code which does not compile.
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();
}
}
}
When compiled with rustc main.rs
It produces these errors
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`.
I understand that this error is caused because weights
is stored on the stack and will be unallocated when the init
function terminates, so the static GRAPH_BUILDER
would contain a pointer to unallocated memory. So I tried to use a Box
instead, which from my understanding should act like malloc in C. But it does not seem to work. How can I get rust to allocate the weights
and xml
variables on the heap, without knowing their sizes at compile time? I.e. What is the rust-equivalent of malloc?
I have read here that you can call clone
to fix this problem. But I don't want to do it because the files I read in are large. And I also don't understand why that would fix the problem. Wouldn't the clone just end up on the stack too?
EDIT: Another important thing I should mention, I need to provide GRAPH_BUILDER
as an argument to the wasi_nn::load function, and it essentially expects it to be of the datatype slice &[&[u8]]
. But I have absolutely no idea how to convert it to this datatype. Here is the continuation of the main function.
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()
};
I am trying to modify this code such that it creates &[&xml.into_bytes(), &weights]
in an initialization function instead of passing it directly.
答案1
得分: 2
Rust等效的malloc
是什么?
这是一个完全不必要的问题,你无需深入研究,你需要实际查看你的代码并考虑发生了什么。
Rust的&T
不是C风格的野指针,它是一个词法范围内的借用智能指针。它只能引用在其整个生命周期内词法有效的数据。
所以我尝试使用Box
,根据我的理解,它应该像C中的malloc
一样工作。但似乎不起作用。
不,因为在Box
内部,你仍然放置了对函数局部数据的引用。这就是Rust抱怨的原因。
你没有将数据复制或移动到堆上,你只是添加了对完全相同问题的间接引用:当函数结束时,weights
和xml
仍然会被丢弃,而你放在Box
中的引用仍然会悬挂,这是Rust不允许的。
但weights
和xml
是Vec<u8>
,因此它们已经是拥有的、堆分配的数据类型。你需要做的就是移动它们到你的东西中:
static mut GRAPH_BUILDER: Option<(Vec<u8>, Vec<u8>)> = None;
[...]
GRAPH_BUILDER = Some((weights, xml));
此外,即使在Rust函数中,你也不希望在extern C
函数中使用unwrap
。据我所知,最好的情况下,它将会立即中止,最坏的情况下,这将是未定义行为。
英文:
> What is the rust-equivalent of malloc?
That is a completely unnecessary question, you don't need to dig further, you need to actually look at your code and think about what's happening.
Rust's &T
is not a C-style wild pointer, it's a lexically-scoped borrowing smart pointer. It can only refer to data that is lexically valid for its entire lifespan.
> So I tried to use a Box instead, which from my understanding should act like malloc in C. But it does not seem to work.
Well no, because inside your box you're still putting references to function-local data. Which is what Rust is complaining about.
You're not copying or moving that data to the heap you're just adding an indirection to the exact same issue: when the function ends, weights
and xml
are still going to be dropped, and the references you put inside your Box
will still be dangling, which Rust does not allow.
But weights
and xml
are Vec<u8>
so they're already owned, heap-allocated data types. All you need to do is move them into your thing:
static mut GRAPH_BUILDER: Option<(Vec<u8>, Vec<u8>)> = None;
[...]
GRAPH_BUILDER = Some((weights, xml));
Also you want to unwrap
in an extern C
function even less than in a Rust function. To my knowledge, at best that will summarily abort, at worst it's UB.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论