如何解决“返回引用当前函数拥有的数据的值"的问题Rust 中的错误? [英] How to solve "returns a value referencing data owned by the current function" error in Rust?
问题描述
我正在尝试编写生成随机表达式的二叉树.我需要随机数和一组函数.我收到一个向量,其中包含树中表达式的函数和深度.在运算符向量中,我还包含一个ELEM"字符串,用于从向量中选择一个随机元素,然后将其更改为浮点数.
I'm trying to code a binary tree that generates random expressions. I need random numbers and a set of functions. I receive a vector with the functions and the depth for the expression in the tree. In the operators vector, I also include a "ELEM" string, this is used to choose a random element from the vector and then change it for a float.
似乎我仍然不明白借用,移动和所有权的确切用法,因为它是一个递归函数,它显示错误说值已被借用并且无法返回局部变量.
It seems I still do not understand the exact use for borrows, moving and ownership, since it is a recursive function, it shows the error saying that value has been borrowed and cannot return a local variable.
use rand::Rng;
struct Expression_Node<'a> {
val: &'a str,
left: Option<Box<Expression_Node<'a>>>,
right: Option<Box<Expression_Node<'a>>>,
}
fn Create_Expression(
operators: Vec<&str>,
p: i32,
) -> std::option::Option<std::boxed::Box<Expression_Node<'_>>> {
if p == 0 {
let value = String::from(rand::thread_rng().gen::<f64>().to_string());
let value2: &str = value.as_ref();
//println!("{:?}", value);
let new_node = Expression_Node {
val: value2,
left: None,
right: None,
};
return Some(Box::new(new_node));
}
let value: &str = *rand::thread_rng().choose(&operators).unwrap();
println!("VAL: {:?}", value);
if value == "ELEM" {
let value = rand::thread_rng().gen::<f64>().to_string();
}
let new_node = Expression_Node {
val: value,
left: Create_Expression(operators.clone(), p - 1),
right: Create_Expression(operators.clone(), p - 1),
};
return Some(Box::new(new_node));
}
错误:
error[E0515]: cannot return value referencing local variable `value`
--> src/lib.rs:22:16
|
15 | let value2: &str = value.as_ref();
| ----- `value` is borrowed here
...
22 | return Some(Box::new(new_node));
| ^^^^^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function
推荐答案
代码最大的问题是ExpressionNode
中&str
的使用.最简单的解决方法是将其更改为 String
.您可以在下面看到对此的修复.这也允许删除所有生命周期注释.
The biggest problem with the code is the use of &str
in the ExpressionNode
.
The simplest fix is to change it to String
. You can see the fix for that below.
This also allows removal of all the lifetime annotations.
该代码中还有一个很重要的修复.
There's also a second fix in that code that is important.
let value: &str = *rand::thread_rng().choose(&operators).unwrap();
if value == "ELEM"{
let value = rand::thread_rng().gen::<f64>().to_string();
}
应该是更新value
,所以if内的赋值不应该包含let
,第一个赋值应该是let mut value
.
should be updating value
, so the assignment within the if should not contain let
, and the first assignment should be let mut value
.
如果您对切换到 String
时发生的所有分配不满意,您还有另外两个选择 - 使用 Cow
字符串或对包含的值类型使用枚举,以便它可以包含字符串或一个浮点数,类似于 - val:Either<&str, f64>
(在这个答案的末尾有一个使用它的版本).
If you're not happy with all the assignments that are happening when switching to a String
, you have two other options - use a Cow
string or use a enum for the contained value type so that it can contain a string or a float, something like - val: Either<&str, f64>
(There's a version using this at the end of this answer).
基于字符串的版本:
use rand::Rng;
#[derive(Debug)]
struct ExpressionNode {
val: String,
left: Option<Box<ExpressionNode>>,
right: Option<Box<ExpressionNode>>,
}
fn create_expression(operators: &[&str], p: i32) -> Option<Box<ExpressionNode>> {
if p == 0 {
let value = String::from(rand::thread_rng().gen::<f64>().to_string());
let new_node = ExpressionNode {
val: value,
left: None,
right: None,
};
return Some(Box::new(new_node));
}
let mut value = rand::thread_rng().choose(&operators).unwrap().to_string();
if value == "ELEM" {
value = rand::thread_rng().gen::<f64>().to_string();
}
let new_node = ExpressionNode {
val: value,
left: create_expression(operators.clone(), p - 1),
right: create_expression(operators.clone(), p - 1),
};
Some(Box::new(new_node))
}
fn main() {
let v = vec!["a", "b", "c", "ELEM"];
let tree = create_expression(&v, 3);
println!("tree = {:?}", tree)
}
为了比较,这里有一个使用 Either<&str, f64>
的版本:
For comparison, here's a version using Either<&str, f64>
:
use either::Either;
use rand::Rng;
#[derive(Debug)]
struct ExpressionNode<'a> {
val: Either<&'a str, f64>,
left: Option<Box<ExpressionNode<'a>>>,
right: Option<Box<ExpressionNode<'a>>>,
}
fn create_expression<'a>(operators: &[&'a str], p: i32) -> Option<Box<ExpressionNode<'a>>> {
if p == 0 {
let value = rand::thread_rng().gen::<f64>();
let new_node = ExpressionNode {
val: Either::Right(value),
left: None,
right: None,
};
return Some(Box::new(new_node));
}
let v = *rand::thread_rng().choose(&operators).unwrap();
let value = if v == "ELEM" {
Either::Right(rand::thread_rng().gen::<f64>())
} else {
Either::Left(v)
};
let new_node = ExpressionNode {
val: value,
left: create_expression(operators.clone(), p - 1),
right: create_expression(operators.clone(), p - 1),
};
Some(Box::new(new_node))
}
fn main() {
let v = vec!["a", "b", "c", "ELEM"];
let tree = create_expression(&v, 3);
println!("tree = {:?}", tree)
}
这篇关于如何解决“返回引用当前函数拥有的数据的值"的问题Rust 中的错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!