Apologies for the cryptic title, I'm not sure how to succinctly describe my problem. Also keep in mind that the details here have been simplified from my actual code.
Suppose I have a struct X
:
struct X {
datum: i32,
attribute: Option<i32>,
}
I also have a function f
that gets a &mut [X]
where all the attribute
fields are None
and computes for each X
the value of attribute
using function fn g(datum: i32, xs: &[X]) -> i32
(g
only uses the datum
field, this is important later). I would like to write the following code:
fn f(xs: &mut [X]) {
for x in xs {
x.attribute = Some(g(x.datum, xs));
}
}
But that runs afoul of the borrow checker, because *xs
is borrowed mutably in the for
loop and again immutably in the call to g
. I see two ways to solve this:
- Loop over indices instead, i.e.
fn f(xs: &mut [X]) {
for i in 0..xs.len() {
xs[i].attribute = Some(g(xs[i].datum, xs));
}
}
- Split
X
in half, letf
andg
take a slice ofi32
instead ofX
and makef
build and return a vector with the attribute values.
Both solutions seem pretty inelegant to me: solution 1 has a lot of indexing and probably ends up checking the slice bounds in every iteration of the loop, while solution 2 is less ergonomic for users of the result and also loses the guarantee that the returned vector is the same length as the initial slice. My question is, assuming there's no better solution that I didn't think of, which one is considered more idiomatic in Rust? Is there even consensus about this matter?