Nano Hash - криптовалюты, майнинг, программирование

Хранить ссылки на себя

Я пытаюсь создать сеть узлов в Rust, где я хочу, чтобы каждый узел в сети знал о каждом другом подключенном узле. Я думал, что это можно сделать со слабыми Rc, например так:

use std::cell::Cell;
use std::cell::RefCell;
use std::rc::Rc;
use std::rc::Weak;

struct Node {
    name: String,
    known_nodes: Rc<RefCell<Vec<Weak<Node>>>>,
}

impl Node {
    fn connect_to_network(&mut self) {
        self.known_nodes
            .borrow_mut()
            .push(Rc::downgrade(&Rc::new(*self)));
    }
}

fn main() {
    let known_nodes = Rc::new(RefCell::new(Vec::new()));
    let node_one = Node {
        name: "node1",
        known_nodes: known_nodes.copy(),
    };
    node_one.connect_to_network();
    let node_two = Node {
        name: "node2",
        known_nodes: known_nodes.copy(),
    };
    node_two.connect_to_network();
}

Однако это дает

не может выйти из заимствованного контента

at:

self.known_senders.borrow_mut().push(Rc::downgrade(&Rc::new(*self)));

Поскольку *self удалено из заимствованного контента в &Rc::new(*self). Любые идеи о том, как каждый узел может отслеживать все остальные узлы в сети?

04.06.2018


Ответы:


1

Вы должны разделить свой узел и свою сеть, потому что ваша сеть должна стать владельцем вашего узла, чтобы создать Rc (или, по крайней мере, она должна принять уже созданный Rc). Вот лучший дизайн, который достигает того, что вы хотите:

use std::rc::Rc;
use std::rc::Weak;
use std::cell::RefCell;

#[derive(Debug)]
struct Node {
    name: String,
}

#[derive(Default, Debug)]
struct Network {
    nodes: Rc<RefCell<Vec<Weak<Node>>>>,
}

impl Network {
    fn add_node(&mut self, node: Node) -> Rc<Node> {
        let node = Rc::new(node);
        self.nodes.borrow_mut().push(Rc::downgrade(&node));

        node
    }
}

fn main() {
    let mut network = Network::default();
    let node_1 = Node { name: "node_1".into() };
    let node_2 = Node { name: "node_2".into() };

    let _node_1 = network.add_node(node_1);
    let _node_2 = network.add_node(node_2);
}

Если вы хотите сохранить ссылку на self, вы можете сделать это:

use std::cell::RefCell;
use std::rc::Rc;
use std::rc::Weak;

type MutableNode = Rc<RefCell<Node>>;
type Network = Rc<RefCell<Vec<Weak<RefCell<Node>>>>>;

struct Node {
    name: String,
    others: Network,
}

impl Node {
    fn new(name: String) -> MutableNode {
        let node = Rc::new(RefCell::new(Node {
            name,
            others: Rc::new(RefCell::new(Vec::new())),
        }));
        {
            let tmp = node.borrow();
            tmp.others.borrow_mut().push(Rc::downgrade(&node));
        }

        node
    }

    fn add_node(&mut self, name: String) -> MutableNode {
        let others = self.others.clone();
        let node = Rc::new(RefCell::new(Node { name, others }));
        self.others
            .borrow_mut()
            .push(Rc::downgrade(&node));

        node
    }

    fn len(&self) -> usize {
        self.others.borrow().len()
    }
}

fn main() {
    let node_0 = Node::new("node_0".into());
    let node_1 = node_0.borrow_mut().add_node("node_1".into());
    let node_2 = node_0.borrow_mut().add_node("node_2".into());

    assert_eq!(node_0.borrow().len(), 3);
    assert_eq!(node_1.borrow().len(), 3);
    assert_eq!(node_2.borrow().len(), 3);
}
04.06.2018

2

Rc::new(value:T) использует value. Ваша функция только заимствует его, поэтому вы не можете вызывать Rc::new(*self)

Я бы порекомендовал вам создать сетевую структуру, подобную приведенному выше ответу. Или вы можете обернуть свой узел в Rc<RefCell<Node>> следующим образом:

use std::cell::RefCell;
use std::rc::Rc;
use std::rc::Weak;

#[derive(Debug)]
struct Node {
    name: String,
    known_nodes: Rc<RefCell<Vec<Weak<RefCell<Node>>>>>,
}

impl Node {
    fn connect_to_network(&mut self,ref_to_self: Weak<RefCell<Node>>) {
        self.known_nodes
            .borrow_mut()
            .push(ref_to_self);
    }
}

fn main() {
    let known_nodes = Rc::new(RefCell::new(Vec::new()));
    let node_one = Rc::new(RefCell::new(Node {
        name: "node1".into(),
        known_nodes: known_nodes.clone(),
    }));
    node_one.borrow_mut().connect_to_network(Rc::downgrade(&node_one));
    let node_two = Rc::new(RefCell::new(Node {
        name: "node2".into(),
        known_nodes: known_nodes.clone(),
    }));
    node_two.borrow_mut().connect_to_network(Rc::downgrade(&node_two));
    println!("{:?}",known_nodes.borrow()[0].upgrade());
    println!("{:?}",known_nodes.borrow()[1].upgrade());
    drop(node_one);
    drop(node_two);
    println!("{:?}",known_nodes.borrow()[0].upgrade());
    println!("{:?}",known_nodes.borrow()[1].upgrade());
}

Что в этом случае вам действительно не нужна функция connect_to_network, вы можете просто добавить каждую Weak<RefCell<Node>> в known_nodes напрямую

Если вы хотите, чтобы код выглядел чище, вы можете ввести псевдоним нового типа для Rc<RefCell<Node>>, как показано ниже.

struct Node {
    name: String,
    known_nodes: Rc<RefCell<Vec<Weak<RefCell<Node>>>>>,
}

type RcNode = Rc<RefCell<Node>>;

trait Connectable {
    fn connect_to_network(&self);
}

impl Connectable for RcNode {
    fn connect_to_network(&self){
        let node = self.borrow_mut();
        node.known_nodes.borrow_mut().push(Rc::downgrade(self));
    }
}

тогда можешь позвонить

let node_one:RcNode = Rc::new(RefCell::new(Node {
    name: "node1".into(),
    known_nodes: known_nodes.clone(),
}));
node_one.connect_to_network();
04.06.2018
Новые материалы

Кластеризация: более глубокий взгляд
Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

Как написать эффективное резюме
Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

Частный метод Python: улучшение инкапсуляции и безопасности
Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

Как я автоматизирую тестирование с помощью Jest
Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..