0

I am trying to build a molecule data structure. Starting with an Atom struct, a molecule Vec stores all of the Atoms (with their coordinates and indices, etc). I also want a Bond struct which will have pairs of Atom structs, and another Vec which stores all of the bonds. I'll do the same for Angle and so on...

Once in the structs, the data will not be mutated, it will just be used to calculate things like bond lengths via methods, but I can't quite work out how to get around the ownership issue.

mvp_molecule.rs

#[derive(Debug)]
struct Atom {
    atomic_symbol: String,
    index: i16,
}

#[derive(Debug)]
struct Bond {
    atom_1: Atom,
    atom_2: Atom,
}

pub fn make_molecule() {
    let mut molecule = Vec::new();
    let mut bonds = Vec::new();

    let atom_1 = Atom {
        atomic_symbol: "C".to_string(),
        index: 0,
    };
    molecule.push(atom_1);
    let atom_2 = Atom {
        atomic_symbol: "H".to_string(),
        index: 1,
    };
    molecule.push(atom_2);
    let bond = Bond {
        atom_1: molecule[0],
        atom_2: molecule[1],
    };
    bonds.push(bond);
}

I think the issue is that Rust thinks I might change an Atom while it's in a Bond, which I won't do. How can I convince Rust of that?

I appreciate this may be a common problem but I'm not learned enough to realise what I should be looking for to solve it. I've looked through a lot of the documentation on references, borrowing and lifetimes but I'm still not quite sure what the issue I'm trying to solve is, or if it's solvable in this way.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
QuantumChris
  • 963
  • 10
  • 21
  • 1
    What's the error? It will be easier for someone to answer if you provide a [reprex]. – Peter Hall Oct 23 '19 at 13:25
  • 2
    As written, `Bond` _owns_ two `Atom`s. If you construct a `Bond` from `Atom`s that are already owned by a `Vec`, then you will need to clone them or else you would invalidate the `Vec` (which would cause an error along the lines of _"cannot move out of index of `std::vec::Vec`"_). Probably you want the fields of `Bond` to be `&Atom`, — or possibly `Rc`, depending on how you need them to be shared. – Peter Hall Oct 23 '19 at 13:29
  • @PeterHall, I've edited in the error I get when compiling – QuantumChris Oct 23 '19 at 13:30
  • 1
    See also: https://stackoverflow.com/questions/30288782/what-are-move-semantics-in-rust/30289815 – Peter Hall Oct 23 '19 at 13:32
  • I tried making the `Bond` struct contain references `&Atom` but that required a lifetime specifier which I couldn't get to work either. – QuantumChris Oct 23 '19 at 13:33
  • 2
    As it stands, no one can answer your question in a way that is useful to other people coming along later. It would devolve into a series of solutions to each new problem, until your very specific code is written for you. Writing a [reprex] will help you focus on, and fully understand, one isolated problem at a time. You can write a new question (or hopefully find an existing answer) if that leads to new problems in your real code. – Peter Hall Oct 23 '19 at 13:43
  • Try to reproduce your error on the [Rust Playground](https://play.rust-lang.org) if possible, otherwise in a brand new Cargo project, then [edit] your question to include the additional info. There are [Rust-specific MRE tips](//stackoverflow.com/tags/rust/info) you can use to reduce your original code for posting here. Thanks! – Shepmaster Oct 23 '19 at 13:50
  • I've rewritten the question to (hopefully) better describe my issue. Let me know if there's anything more I should change, thanks! – QuantumChris Oct 23 '19 at 13:55
  • *as minimal and clear as possible.* — are the **5** fields of `Atom` required to reproduce the problem? I expect you can remove all of them. That's the first most obvious thing I see. Make sure to try all of the reduction tips listed. – Shepmaster Oct 23 '19 at 13:56
  • Also, you might be interested in the [`vec!`](https://doc.rust-lang.org/std/macro.vec.html) macro. – Shepmaster Oct 23 '19 at 13:58
  • Updated again. Also, I create an empty `vec` and add to it as a file is read, so I use `vec::new()` first. `vec!` is only for initialising a non-empty `vec`, isn't it? – QuantumChris Oct 23 '19 at 14:00
  • The post does not contain the error you are asking about. The example here does not do any incremental reading of a file, so there's no reason you cannot use `vec!`. So long as it continues to produce the same error. – Shepmaster Oct 23 '19 at 14:02
  • It looks like your question might be answered by the answers of [What does “cannot move out of index of” mean?](https://stackoverflow.com/q/27904864/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Oct 23 '19 at 14:04
  • For example, I think your code can be fully reduced to [this](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b516b45c18ff27e758784d02c713738a). – Shepmaster Oct 23 '19 at 14:06
  • I don't think the answers to the above are what I'm after. Unless the only solution is to have bonds be a vec of references? But then I go back to the issue of a missing lifetime specifier – QuantumChris Oct 23 '19 at 14:11
  • References is an answer, cloning is an answer, reference-counting is an answer. See also [Need holistic explanation about Rust's cell and reference counted types](https://stackoverflow.com/q/45674479/155423). – Shepmaster Oct 23 '19 at 14:16
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/201334/discussion-between-shepmaster-and-quantumchris). – Shepmaster Oct 23 '19 at 14:21

0 Answers0