简体   繁体   English

Rust 具有许多可变引用的回溯树结构

[英]Rust backtrace tree structure with many mutable references

I am trying to build a data structure that is able to hold content of a evolutionary simulation.我正在尝试构建一个能够保存进化模拟内容的数据结构。 I found a bunch of nasty solutions to successively grow the tree and then enable backtracing.我发现了一堆令人讨厌的解决方案来连续种植树,然后启用回溯。 It works, however I am not sure if I am generating a memory leak in the backtracing part of the code.它有效,但我不确定我是否在代码的回溯部分生成了 memory 泄漏。

I appended most of the code that is not the constructors etc., specifically I am unsure about Descendant::get_sequence() as I have to use unsafe code there.我附加了大部分不是构造函数等的代码,特别是我不确定Descendant::get_sequence()因为我必须在那里使用不安全的代码。

Question: Is there a memory leak in Descendant::get_sequence() ?问题: Descendant::get_sequence()中是否存在 memory 泄漏?

use derivative::Derivative;
use std::cell::RefCell;
use std::rc::Rc;

#[derive(Derivative)]
#[derivative(Debug)]
pub enum Haplotype {
    Wildtype(Wildtype),
    Descendant(Descendant),
}

#[derive(Derivative)]
#[derivative(Debug)]
pub struct Wildtype {
    #[derivative(Debug = "ignore")]
    reference: Option<Rc<RefCell<Haplotype>>>,
    sequence: Vec<u8>,
    descendants: Vec<Rc<RefCell<Haplotype>>>,
}

#[derive(Derivative)]
#[derivative(Debug)]
pub struct Descendant {
    #[derivative(Debug = "ignore")]
    reference: Option<Rc<RefCell<Haplotype>>>,
    #[derivative(Debug = "ignore")]
    ancestor: Rc<RefCell<Haplotype>>,
    #[derivative(Debug = "ignore")]
    wildtype: Rc<RefCell<Haplotype>>,
    descendants: Vec<Rc<RefCell<Haplotype>>>,
    position: usize,
    change: u8,
}

impl Haplotype {
    pub fn get_reference(&self) -> &Rc<RefCell<Haplotype>> {
        let option = match self {
            Haplotype::Wildtype(wt) => &wt.reference,
            Haplotype::Descendant(ht) => &ht.reference,
        };
        match option {
            Some(reference) => &reference,
            None => {
                eprintln!("Haplotype incorrectly initialized.");
                std::process::exit(-1);
            }
        }
    }

    pub fn get_base(&self, position: usize) -> u8 {
        match self {
            Haplotype::Wildtype(wt) => wt.get_base(position),
            Haplotype::Descendant(ht) => ht.get_base(position),
        }
    }

    pub fn get_sequence(&self) -> Vec<u8> {
        match self {
            Haplotype::Wildtype(wt) => wt.get_sequence(),
            Haplotype::Descendant(ht) => ht.get_sequence(),
        }
    }

    pub fn get_length(&self) -> usize {
        match self {
            Haplotype::Wildtype(wt) => wt.get_length(),
            Haplotype::Descendant(ht) => ht.get_length(),
        }
    }
}

impl Wildtype {
    pub fn get_reference(&self) -> &Rc<RefCell<Haplotype>> {
        match &self.reference {
            Some(reference) => &reference,
            None => {
                eprintln!("Haplotype incorrectly initialized.");
                std::process::exit(-1);
            }
        }
    }

    pub fn get_base(&self, position: usize) -> u8 {
        self.sequence[position]
    }

    pub fn get_sequence(&self) -> Vec<u8> {
        self.sequence.to_vec()
    }

    pub fn get_length(&self) -> usize {
        self.sequence.len()
    }
}

impl Descendant {
    pub fn get_reference(&self) -> &Rc<RefCell<Haplotype>> {
        match &self.reference {
            Some(reference) => &reference,
            None => {
                eprintln!("Haplotype incorrectly initialized.");
                std::process::exit(-1);
            }
        }
    }

    pub fn get_base(&self, position: usize) -> u8 {
        if self.position == position {
            return self.change;
        }
        self.ancestor.as_ref().borrow().get_base(position)
    }

    pub fn get_sequence(&self) -> Vec<u8> {
        let mut sequence = vec![0; self.get_length()];
        let mut current = Rc::into_raw(Rc::clone(self.get_reference()));
        unsafe {
            while let Haplotype::Descendant(ht) = &*(*current).borrow() {
                if sequence[ht.position] == 0 {
                    sequence[ht.position] = ht.change
                }
                Rc::from_raw(current);
                current = Rc::into_raw(Rc::clone(&ht.ancestor));
            }
            if let Haplotype::Wildtype(wt) = &*(*current).borrow() {
                for (position, symbol) in wt.sequence.iter().enumerate() {
                    if sequence[position] == 0 {
                        sequence[position] = *symbol;
                    }
                }
            }
            Rc::from_raw(current);
            return sequence;
        }
    }

    pub fn get_length(&self) -> usize {
        self.wildtype.borrow().get_length()
    }
}

You can restructure your code to eliminate the need of unsafe :您可以重组代码以消除对unsafe的需求:

pub fn get_sequence(&self) -> Vec<u8> {
    let mut sequence = vec![0; self.get_length()];
    let mut current = Rc::clone(self.get_reference());
    while let Haplotype::Descendant(ht) = &*Rc::clone(&current).borrow() {
        if sequence[ht.position] == 0 {
            sequence[ht.position] = ht.change;
        }
        current = Rc::clone(&ht.ancestor);
    }
    if let Haplotype::Wildtype(wt) = &*(*current).borrow() {
        for (position, symbol) in wt.sequence.iter().enumerate() {
            if sequence[position] == 0 {
                sequence[position] = *symbol;
            }
        }
    }
    return sequence;
}

Note that we have to borrow ht from a clone of current in the while let loop to satisfy the borrow checker, as explained here .请注意,我们必须在while let循环中从current的克隆中借用ht以满足借用检查器的要求,如此处所述

Playground 操场

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM