如何解决“返回引用当前函数拥有的数据的值"的问题Rust 中的错误? [英] How to solve "returns a value referencing data owned by the current function" error in Rust?

查看:78
本文介绍了如何解决“返回引用当前函数拥有的数据的值"的问题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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆