【问题标题】:How to solve "returns a value referencing data owned by the current function" error in Rust? [duplicate]如何解决 Rust 中的“返回引用当前函数拥有的数据的值”错误? [复制]
【发布时间】:2019-07-12 11:21:13
【问题描述】:

我正在尝试编写生成随机表达式的二叉树。我需要随机数和一组函数。我收到一个向量,其中包含树中表达式的函数和深度。在操作符向量中,我还包含一个“ELEM”字符串,用于从向量中选择一个随机元素,然后将其更改为浮点数。

似乎我仍然不明白借用、移动和所有权的确切用途,因为它是一个递归函数,它会显示错误说值已被借用并且无法返回局部变量。

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

【问题讨论】:

  • 随机生成的值需要超过函数体。可能是在表达式中存储拥有的字符串而不是切片?
  • Idiomatic Rust 使用snake_case 表示变量、方法、宏和字段; UpperCamelCase 用于类型和枚举变体; SCREAMING_SNAKE_CASE 用于静态和常量。请改用ExpressionNodecreate_expression
  • 没有理由使用std::option::Optionstd::boxed::Box — 这些都在前奏中,不需要完全限定(实际上你并没有在任何地方限定它们)。在块的末尾使用显式的return 也是不习惯的。

标签: rust


【解决方案1】:

代码最大的问题是&amp;strExpressionNode中的使用。 最简单的解决方法是将其更改为String。您可以在下面看到修复程序。 这也允许删除所有生命周期注释。

该代码中还有第二个重要的修复。

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

如果您对切换到 String 时发生的所有分配不满意,您还有两个选择 - 使用 Cow 字符串或使用枚举作为包含的值类型,以便它可以包含一个字符串或一个浮点数,比如 - val: Either&lt;&amp;str, f64&gt;(在这个答案的末尾有一个使用这个的版本)。

基于字符串的版本:

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&lt;&amp;str, f64&gt;的版本:

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)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多