Rust函数的行为很奇怪

vbkedwbf  于 2022-12-04  发布在  其他
关注(0)|答案(1)|浏览(173)

我有一个实现如下:

use crate::queue::{Task, WorkQueue};
use digest::consts::U32;
use digest::generic_array::typenum::Pow;
use sha2::digest::generic_array::GenericArray;
use sha2::{Digest, Sha256};
use std::fmt::Write;
use std::ops::Add;
use std::sync;

pub type Hash = GenericArray<u8, U32>;

#[derive(Debug, Clone)]
pub struct Block {
    pub prev_hash: Hash,
    pub generation: u64,
    pub difficulty: u8,
    pub data: String,
    pub proof: Option<u64>,
}

impl Block {
    pub fn mine_range(self: &Block, workers: usize, start: u64, end: u64, chunks: u64) -> u64 {
        // TODO: with `workers` threads, check proof values in the given range, breaking up
        // into `chunks` tasks in a work queue. Return the first valid proof found.
        // HINTS:
        // - Create and use a queue::WorkQueue.
        // - Use sync::Arc to wrap a clone of self for sharing.
        unimplemented!()
    }

    pub fn mine_for_proof(self: &Block, workers: usize) -> u64 {
        let range_start: u64 = 0;
        let range_end: u64 = 8 * (1 << self.difficulty); // 8 * 2^(bits that must be zero)
        let chunks: u64 = 2345;
        self.mine_range(workers, range_start, range_end, chunks)
    }

    pub fn mine(self: &mut Block, workers: usize) {
        self.proof = Some(self.mine_for_proof(workers));
    }
}

struct MiningTask {
    block: sync::Arc<Block>,
    // TODO: more fields as needed
    workers: usize
}

impl Task for MiningTask {
    type Output = u64;

    fn run(&self) -> Option<u64> {
        // TODO: what does it mean to .run?
        self.block.mine(self.workers);
        let result = self.block.proof;
        return result;
    }
}

现在,如果我从run中取出返回状态,如下所示:

impl Task for MiningTask {
    type Output = u64;

    fn run(&self) -> Option<u64> {
        // TODO: what does it mean to .run?
        self.block.mine(self.workers);
        let result = self.block.proof;
        //return result;
    }
}

然而这样的借款错误是不存在的:

impl Task for MiningTask {
    type Output = u64;

    fn run(&self) -> Option<u64> {
        // TODO: what does it mean to .run?
        self.block.mine(self.workers);
        let result = self.block.proof;
        return result;
    }
}

它给我:无法借用Arc中的数据,因为需要通过取消引用修改可变特性DerefMut,但未对Arc<Block>实现该特性
我不明白为什么返回某个东西会导致借用,我该如何修复这个问题?最好是没有互斥库还是没有借用?即使我尝试克隆自我,它仍然执行借用,我非常困惑。

o2g1uqev

o2g1uqev1#

在MiningTask::run方法中,您尝试返回Block结构的proof字段。此字段存储在Option类型中,这意味着它要么是包含proof的Some值,要么是None值(如果尚未找到)。
当您尝试传回这个值时,编译器无法推断您是要传回证明字段的指涉,还是证明值的复本。若要传回证明字段的指涉,您必须使用Option::as_ref方法,将Option型别转换成指涉的Option。例如:

fn run(&self) -> Option<&u64> {
    self.block.mine(self.workers);
    let result = self.block.proof.as_ref();
    return result;
}

或者,您可以使用Option::copied方法将Option类型转换为基础类型(在本例中为u64)的Option,以传回校样值的副本。例如:

fn run(&self) -> Option<u64> {
    self.block.mine(self.workers);
    let result = self.block.proof.copied();
    return result;
}

在您提供的程式码中,您已经完全移除了return陈述式。这表示MiningTask::run方法永远会传回None,因为传回型别是Option,而且方法主体中没有return陈述式。这不会造成借位错误,因为Block结构是 Package 在Arc中,允许对相同数据的多重指涉。
然而,以这种方式删除return语句意味着run方法将不返回mine方法找到的proof值。这可能不是您所希望的行为,这取决于您试图对MiningTask结构体做什么。

更新日期:

在您提供的代码中,run方法具有类型签名fn run(&self)-〉Option,这意味着它返回一个Option值。Option不是迭代器,因此不能与for循环语法一起使用。
如果你想使用for循环来迭代一个范围内可能的证明值,你需要改变run方法来返回一个迭代器而不是一个Option。下面是一个例子来说明你如何做到这一点:

impl Task for MiningTask {
    type Output = u64;

    fn run(&self) -> impl Iterator<Item = u64> {
        let range_start: u64 = 0;
        let range_end: u64 = 8 * (1 << self.block.difficulty);
        let chunk_size: u64 = 2345;

        (range_start..range_end).step_by(chunk_size as usize)
    }
}

在这个例子中,run方法返回一个迭代器,该迭代器产生指定范围内的证明值,按照给定的块大小步进。然后,你可以在for循环中使用这个迭代器来迭代证明值,并检查每个值的有效性。下面是一个例子:

impl Block {
    pub fn mine_range(self: &Block, workers: usize, start: u64, end: u64, chunks: u64) -> u64 {
        let task = MiningTask {
            block: sync::Arc::new(self),
            workers: workers,
        };

        let queue = WorkQueue::new(task, workers);

        // Iterate over the proof values in the given range
        for proof in queue.run() {
            let mut hasher = Sha256::new();
            let mut hash_input = String::new();
            write!(hash_input, "{}{}{}{}{}", self.prev_hash, self.generation, self.difficulty, self.data, proof).unwrap();
            hasher.update(hash_input);
            let hash = hasher.finalize();

            // Check if the hash is valid
            if hash[0] == 0 && hash[1] == 0 && hash[2] == 0 {
                return proof;
            }
        }

        // If no valid proof was found, return 0
        0
    }
}

相关问题