【问题标题】:How can I allow multiple owners while enabeling mutation of value?如何在启用价值突变的同时允许多个所有者?
【发布时间】:2021-10-05 19:05:13
【问题描述】:

我有一个 Enum,名为 NodeType,它允许 Network 的值(网络) 或 Mesh(Mesh)。 Network 和 Mesh 都是 unknown size 的结构。一个网络实例包含一个节点结构的二维向量,其中包含一个 NodeType 枚举,它允许网络包含其他网络或网格结构。网格做一些任意的功能。

考虑以下 Network,它的 NodeType 向量大小为 1 x 3。内容为:[Mesh, Network0, Network1]。 first 元素(网格),做了一些事情并且无关紧要。 Second 元素 Network0 已创建,并在实例化时分配了 NodeType(Mesh)。与之前包含 Mesh 的 Network 一样,这无关紧要。

第三个元素 Network1 的创建方式与 Network0 相同,在创建时定义了 NodeType(Mesh)。但是,我们现在要向 Network1 的 NodeType Vector 添加一个新值。我的问题是我无法为递归结构而不是递归循环的“根”分配值。在任何给定时间,一个子网络可能会在多个父网络中被引用。我无法执行这些 NodeType 的深层复制,因为它可能(无限)大。

我看到的问题是一个节点包含一个 Arc。但这些都是必需的,因为 Arc 允许多个 Network 引用同一个 Struct 实例,而 RwLock 允许在线程化时进行管理。

以下是使用的三个结构,以及实例化上述场景的主要结构:

节点

#[derive(Debug)]
pub(crate) struct Node {
    guid: Uuid,
    node: Arc<RwLock<NodeType>>,
}

impl Node {
    pub(crate) fn new(subnet: NodeType) -> Node {
        Node {
            guid: Uuid::new_v4(),
            node: Arc::new(RwLock::new(subnet))
        }
    }

    pub(crate) fn node(self) -> Arc<RwLock<NodeType>> {
        self.node.clone()
    }
}

#[derive(Debug)]
pub(crate) enum NodeType {
    Network(Network),
    Mesh(Mesh),
}

网络

#[derive(Debug)]
pub(crate) struct Network {
    guid: Uuid,
    pub(crate) subnet: Vec<Vec<Node>>,
}

impl Network {
    pub(crate) fn new(subnet: NodeType) -> Network {
        Network {
            guid: Uuid::new_v4(),
            subnet: vec![vec![Node::new(subnet)]],
        }
    }
}

网格

#[derive(Debug, )]
pub(crate) struct Mesh {
    guid: Uuid,
}

impl Mesh {
    pub(crate) fn new() -> Mesh {
        Mesh {
            guid: Uuid::new_v4(),
        }
    }
}

主要

    //Creates A NodeType(Mesh)
    let a = NodeType::Mesh(Mesh::new());
    //Assigns the NodeType(Mesh) as the Second Element
    let mut agent0 = Network::new(a);

    //Creates a NodeType(Network) that Contains a Single Mesh
    let b = NodeType::Network(Network::new(NodeType::Mesh(Mesh::new())));
    //Assigns A NodeType(Network) that Contains a NodeType(Mesh) as the first element.
    agent0.subnet[0].push(Node::new(b));

    //Creates a NodeType(Network), Containing A NodeType(Mesh)
    let c = NodeType::Network(Network::new(NodeType::Mesh(Mesh::new())));
    //Assigns A NodeType(Network) that Contains a NodeType(Mesh) as the third element.
    agent0.subnet[0].push(Node::new(c));

    //An Attempt to append an additional Mesh to the Third Element's NodeType Vector. (Not Currently Working)
    let value = (*agent0.subnet[0][2].node()).get_mut();
    if let NodeType::Network(mut content) = value {
        // let d = NodeType::Mesh(Mesh::new());
        // content.subnet[0].push(Arc::new(RwLock::new(NodeType::Mesh(Mesh::new()))))
    }

收到的错误是:

let i = (*agent0.subnet[0][2].node()).get_mut();
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable

trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Arc<async_std::sync::RwLock<NodeType>>`

我希望我的问题很清楚,我决定冒险过度解释而不是替代方案。

【问题讨论】:

  • 在playground 上重现您的代码,看来您只是有简单的类型不匹配错误(例如,未锁定RwLock)并且整体设计没有问题。如果这是唯一有问题的问题,请包括错误,以便人们可以直接解决它们。
  • 我会做出适当的修改。完成了,我还把损坏的代码分解了一点。

标签: multithreading rust neural-network smart-pointers


【解决方案1】:

我认为这里的问题是你有一个Arc&lt;RwLock&lt;NodeType&gt;&gt;,但是当你只有一个不可变的引用时你试图get_mut()。正如the documentation for RwLock 所说,

use std::sync::RwLock;

let lock = RwLock::new(5);

// many reader locks can be held at once
{
    let r1 = lock.read().unwrap();
    let r2 = lock.read().unwrap();
    assert_eq!(*r1, 5);
    assert_eq!(*r2, 5);
} // read locks are dropped at this point

// only one write lock may be held, however
{
    let mut w = lock.write().unwrap();
    *w += 1;
    assert_eq!(*w, 6);
} // write lock is dropped here

所以您的代码缺少的是Arc 只为您提供了一个对您的RwLock 的非可变 引用,这意味着您需要在其上调用write,然后@ 987654329@ 因为可能的结果,根据上面的示例来获取对内部NodeType 的可变引用。

编辑:我认为这是您在最后一部分中想要的。虽然不是 100% 肯定,因为它不会克隆您的 Arc,但我认为这是您尝试要做的:

    //An Attempt to append an additional Mesh to the Third Element's NodeType Vector.
    let mynode = &(agent0.subnet[0][2]);
    let mut locker = mynode.node.write().unwrap();
    if let NodeType::Network(content) = &mut *locker {
        let my_mesh_nodetype = NodeType::Mesh(Mesh::new());
        let my_fresh_node = Node::new(my_mesh_nodetype);
        content.subnet[0].push(my_fresh_node);
    }

根据您在代码中的评论,我认为这是正确的。

【讨论】:

  • 感谢您的回复。不幸的是,这会提示另一个错误“发生移动是因为值的类型为Node,它没有实现Copy 特征”。这是在尝试使用以下命令提取值之后: *agent0.subnet[0][2].node().write().unwrap();我不想实现复制特征,因为我认为复制结构的递归系统会很昂贵。
  • 您的if let 可能也需要更改,以便您可以随时获取引用,而不仅仅是底层类型。无论如何,write 调用是您所需要的,因为即使是示例也表明您有某种“指针/引用”,并且您必须考虑到您没有来自 mut 的引用Arc
  • 感谢您的建议。我必须承认,我不太清楚如何进行这样的高级比赛 - 但今天我会学习。
  • 不客气。它让我觉得它不完整,所以花时间在它上面。我希望它有所帮助。我只希望 rust Guru 出现并修复我的代码以压缩它,因为我认为有一种更简洁的方法,比如 deref_mut 或其他东西。不包括声明的多行爆炸,因为这并不重要,因为它当然会被编译掉。
猜你喜欢
  • 1970-01-01
  • 2017-03-12
  • 2018-03-13
  • 1970-01-01
  • 2021-11-28
  • 1970-01-01
  • 2019-08-21
  • 2019-06-18
  • 2020-04-19
相关资源
最近更新 更多