This question already has answers here:
How do I write an iterator that returns references to itself?
(4 answers)
Closed 2 years ago.
For Advent of Code Day 17 (problem statement isn't super important), what I want to do is have a type:
#[derive(Debug, Clone)]
struct Cubes {
active: HashSet<Vec<i32>>,
}
And create an Iterator that yields out successive instances of that type. I can (did) implement this:
impl Iterator for Cubes {
type Item = Cubes;
fn next(&mut self) -> Option<Cubes> { ... }
}
Which works fine, but is pretty expensive since what I end up doing is both modifying the Cubes locally and also returning a copy of it.
What I'd like do is have the Iterator mutate its internal state and hand out a reference to it, so that I don't need to make any copies.
Even in the most trivial case of like an infinite iterator that just hands out a reference, I can't come up with a formulation of this that checks:
// this doesn't actually compile
fn iter(cc: &mut Cubes) -> impl Iterator<Item=&Cubes> {
std::iter::from_fn(move ||{
Some(&*cc)
})
}
whereas what I'm doing is roughly equivalent to this (which does compile, but I am trying to improve):
fn iter(cc: ConwayCubes) -> impl Iterator<Item=ConwayCubes> {
std::iter::from_fn(move ||{
Some(cc.clone())
})
}
I suppose I could also restructure the problem to hand out something like Rc<Cubes>, which would still do copies but those copies would be cheap, but I'm curious if there's a way to do this with references.
As mentioned in the comments, the issue is that you cannot return a reference to something while subsequently wanting to mutate it. Because that something is still being "borrowed" and referenced elsewhere.
If that was possible, then suppose you collect()ed everything into a Vec<&Cubes>, then if that resulted in a Vec<&Cubes> with 3 items. Then given that it's 3 references to the same instance, then all 3 items would have the same state as the last item.
In short you'd not end up with x, f(x), f(f(x)) as you want, but instead f(f(x)), f(f(x)), f(f(x))
Since you want less cloning, then it sounds more like you just want an fn next_state(&mut self) method. Then you could iterate and call cubes.next_state() which would update cubes to its next state, while no needless cloning would occur.
impl Cubes {
fn next_state(&mut self) {
...
}
}
fn main() {
for _ in 0..10 {
// do something with cubes
cubes.next_state();
}
}
Along the lines of what you already did, you could then create an iter_states() method using iter::from_fn(), which calls next_state() and returns a clone.
impl Cubes {
fn iter_states(&self) -> impl Iterator<Item = Cubes> {
let mut next = self.clone();
iter::from_fn(move || {
let current = next.clone();
next.next_state();
Some(current)
})
}
}
Alternatively, you could also introduce a custom CubesIter Iterator type. Then you can impl IntoIterator for Cubes which converts Cubes into an Iterator.
struct CubesIter {
next: Cubes,
}
impl Iterator for CubesIter {
type Item = Cubes;
fn next(&mut self) -> Option<Self::Item> {
let current = self.next.clone();
self.next.next_state();
Some(current)
}
}
impl IntoIterator for Cubes {
type Item = Cubes;
type IntoIter = CubesIter;
fn into_iter(self) -> Self::IntoIter {
CubesIter { next: self }
}
}
This would then allow you to do:
let cubes: Cubes = ...;
for state in cubes {
...
}
Note that the above will iterate indefinitely. So you'd have to add some stop state or condition.
Related
In my model, I have a Petgraph graph which stores as nodes a struct with fields as followed:
struct ControlBloc
{
name:String,
message_inbox:Vec<MessageObj>,
blocked:bool,
instruct:String,
inbox_capacity:f64,
buffer:Vec<MessageObj>,
number_discarded:u32,
clock_queue:SendingQueue,
clock_speed:f64,
}
In it there is a field called instruct in which I want to store instructions. I want to code the model in a way such that after some time, all the nodes will execute the instructions that are stored in the struct. Instructions can be for example send messages to other nodes, computing something... I want something versatile.
Is there a way to store functions as fields in a struct? and then after some time, the function stored can be called and whatever function will be executed?
One way that I see doing this is maybe using enum to store all the function names then using a function to map whatever enum to the corresponding function, for example:
enum FuncName {
SendMessage,
ComputeSize,
StoreSomething,
DoNothing,
}
fn exec_function(func:FuncName)
{
match func {
FuncName::SendMessage => send_message_function(input1,input2),
FuncName::ComputeSize => compute_size_function(input1,input2,input3),
FuncName::StoreSomething => store_something_funtion(input1),
FuncName::DoNothing => (),
}
}
However in this case you can't really customize the inputs of the FuncName function and they either have to be always preset to the same thing or in the input of exec_function you add all the different inputs fields of all the functions in FuncName but that seems rather overkill, even then, I dont really see how to pass them and store in the struct.
Is there then a way to directly add the functions or something in the struct? I know I'm breaking many Rust rules but say for example I had a variable already declared let bloc = ControlBloc::new(...); then you could set the function as for example bloc.instruct = send_message_function(node1,node2); and then when you called bloc.instruct then that would call whatever function is stored there.
Is something like this possible or am I dreaming or like very difficult (I am still learning the language)?
What you can do is storing Box<dyn Fn()> in your struct:
struct Foo {
instruct: Box<dyn Fn(Vec<i32>)>
}
fn sum(vec: Vec<i32>) {
let sum: i32 = vec.into_iter().sum();
println!("{}", sum);
}
fn main() {
let foo = Foo {
instruct: Box::new(|vec| {
let sum: i32 = vec.into_iter().sum();
println!("{}", sum);
})
};
(foo.instruct)(vec![1, 2, 3, 4]);
let foo = Foo {
instruct: Box::new(sum)
};
(foo.instruct)(vec![1, 2, 3, 4]);
}
Fn is implemented automatically by closures which only take immutable references to captured variables or don’t capture anything at all, as well as (safe) function pointers (with some caveats, see their documentation for more details). Additionally, for any type F that implements Fn, &F implements Fn, too.
#EDIT
In my example I used Vec<i32> as an abstract for multiple arguments. However if you are going to have some set of instructions that have different count of arguments, but within itself always the same, you might consider creating a trait Instruct and create struct for every different instruct that will implement this.
Playground
struct Foo<T> {
instruct: Box<dyn Instruct<T>>
}
trait Instruct<T> {
fn run(&self) -> T;
}
struct CalcSum {
f: Box<dyn Fn() -> i32>
}
impl CalcSum {
fn new(arg: Vec<i32>) -> CalcSum {
CalcSum {
f: Box::new(move || arg.iter().sum::<i32>()),
}
}
}
impl Instruct<i32> for CalcSum {
fn run(&self) -> i32 {
(self.f)()
}
}
I'm trying quite complex stuff with Rust where I need the following attributes, and am fighting the compiler.
Object which itself lives from start to finish of application, however, where internal maps/vectors could be modified during application lifetime
Multiple references to object that can read internal maps/vectors of an object
All single threaded
Multiple nested iterators which are map/modified in lazy manner to perform fast and complex calculations (see example below)
A small example, which already causes problems:
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Weak;
pub struct Holder {
array_ref: Weak<RefCell<Vec<isize>>>,
}
impl Holder {
pub fn new(array_ref: Weak<RefCell<Vec<isize>>>) -> Self {
Self { array_ref }
}
fn get_iterator(&self) -> impl Iterator<Item = f64> + '_ {
self.array_ref
.upgrade()
.unwrap()
.borrow()
.iter()
.map(|value| *value as f64 * 2.0)
}
}
get_iterator is just one of the implementations of a trait, but even this example already does not work.
The reason for Weak/Rc is to make sure that multiple places points to object (from point (1)) and other place can modify its internals (Vec<isize>).
What is the best way to approach this situation, given that end goal is performance critical?
EDIT:
Person suggested using https://doc.rust-lang.org/std/cell/struct.Ref.html#method.map
But unfortunately still can't get - if I should also change return type - or maybe the closure function is wrong here
fn get_iterator(&self) -> impl Iterator<Item=f64> + '_ {
let x = self.array_ref.upgrade().unwrap().borrow();
let map1 = Ref::map(x, |x| &x.iter());
let map2 = Ref::map(map1, |iter| &iter.map(|y| *y as f64 * 2.0));
map2
}
IDEA say it has wrong return type
the trait `Iterator` is not implemented for `Ref<'_, Map<std::slice::Iter<'_, isize>, [closure#src/bin/main.rs:30:46: 30:65]>>`
This won't work because self.array_ref.upgrade() creates a local temporary Arc value, but the Ref only borrows from it. Obviously, you can't return a value that borrows from a local.
To make this work you need a second structure to own the Arc, which can implement Iterator in this case since the produced items aren't references:
pub struct HolderIterator(Arc<RefCell<Vec<isize>>>, usize);
impl Iterator for HolderIterator {
type Item = f64;
fn next(&mut self) -> Option<f64> {
let r = self.0.borrow().get(self.1)
.map(|&y| y as f64 * 2.0);
if r.is_some() {
self.1 += 1;
}
r
}
}
// ...
impl Holder {
// ...
fn get_iterator<'a>(&'a self) -> Option<impl Iterator<Item=f64>> {
self.array_ref.upgrade().map(|rc| HolderIterator(rc, 0))
}
}
Alternatively, if you want the iterator to also weakly-reference the value contained within, you can have it hold a Weak instead and upgrade on each next() call. There are performance implications, but this also makes it easier to have get_iterator() be able to return an iterator directly instead of an Option, and the iterator written so that a failed upgrade means the sequence has ended:
pub struct HolderIterator(Weak<RefCell<Vec<isize>>>, usize);
impl Iterator for HolderIterator {
type Item = f64;
fn next(&mut self) -> Option<f64> {
let r = self.0.upgrade()?
.borrow()
.get(self.1)
.map(|&y| y as f64 * 2.0);
if r.is_some() {
self.1 += 1;
}
r
}
}
// ...
impl Holder {
// ...
fn get_iterator<'a>(&'a self) -> impl Iterator<Item=f64> {
HolderIterator(Weak::clone(&self.array_ref), 0)
}
}
This will make it so that you always get an iterator, but it's empty if the Weak is dead. The Weak can also die during iteration, at which point the sequence will abruptly end.
I have a struct Folder. I have a method called contents. I want that method to return an object that supports IntoIterator so that the caller can just go
for x in folder.contents(){
...
}
The Item type is (since this is what the hashmap iterator returns - see a little lower)
(&OsString, &FileOrFolder)
where FileOrFolder is an enum
enum FileOrFolder{
File(File),
Folder(Folder)
}
The iterator itself needs to first enumerate a HashMap<OSString, FileOrFolder> owned by the folder and then second, enumerate a Vec<File>. The Vec of files is created on the fly by the contents fn or by the IntoIterator call, whatever works. I tried simply using chain but quickly realized that wasn't going to work. So my rough sketch of what I am trying to do is this:
// the iterator
pub struct FFIter {
files: Vec<FileOrFolder>,
files_iter:Box<dyn Iterator<Item=FileOrFolder>>,
dirs: Box<dyn Iterator<Item = (&OsString, &FileOrFolder)>>,
dirs_done:bool
}
// the thing returned by the contents fn
struct FolderContents{
folder:&Folder
}
// make it iterable
impl IntoIterator for FolderContents {
type Item =(&OsString, &FileOrFolder);
type IntoIter = FFIter;
fn into_iter(self) -> Self::IntoIter {
let files = self.folder.make_the_files()
FFIter {
files: files, // to keep files 'alive'
files_iter: files.iter(),
dirs: Box::new(self.hashmap.iter()),
dirs_done:false
}
}
}
impl Iterator for FFIter {
type Item = (&OsString, &FileOrFolder);
fn next(&mut self) -> Option<(&OsString, &FileOrFolder)> {
None // return empty, lets just get the skeleton built
}
}
impl Folder{
pub fn contents(&self) -> FolderContents{
FolderContents{folder:&self}
}
}
I know this is full of errors, but I need to know if this is doable at all. As you can see I am not even trying to write the code that returns anything. I am just trying to get the basic outline to compile.
I started arm wrestling with the lifetime system and got to the point where I had this
error[E0658]: generic associated types are unstable
--> src\state\files\file_or_folder.rs:46:5
|
46 | type Item<'a> =(&'a OsString, &'a FileOrFolder);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
Which kinda sucked as that is what the compiler said I should do.
I am happy to keep ploughing away at this following the suggestions from the compiler / reading / ... But in the past I have posted a question along these lines and been told - 'of course it can't be done'. So should I be able to make this work?
The Folder type is not Copy and expensive to clone. The File type is simple (string and i64), Copy and Clone
I know I could simply make the caller call two different iterations and merge them, but I am trying to write a transparent replacement module to drop into a large existing codebase.
If somebody says that chain() should work that's great, I will have another go at that.
EDIT Jmp said chain should work,
heres what I tried
pub fn contents(&self) -> Box<dyn Iterator<Item = (&OsString, &FileOrFolder)> + '_> {
let mut files = vec![];
if self.load_done {
for entry in WalkDir::new(&self.full_path)
.max_depth(1)
.skip_hidden(false)
.follow_links(false)
.into_iter()
{
let ent = entry.unwrap();
if ent.file_type().is_file() {
if let Some(name) = ent.path().file_name() {
files.push((
name.to_os_string(),
FileOrFolder::File(File {
name: name.to_os_string(),
size: ent.metadata().unwrap().len() as u128,
}),
));
}
}
}
};
Box::new(
self.contents
.iter()
.map(|(k, v)| (k, v))
.chain(files.iter().map(|x| (&x.0, &x.1))),
)
}
but the compiler complains, correctly, that 'files' get destroyed at the end of the call. What I need is for the vec to be held by the iterator and then dropped at the end of the iteration. Folder itself cannot hold the files - the whole point here is to populate files on the fly, its too expensive, memory wise to hold them.
You claim that files is populated on the fly, but that's precisely what your code is not doing: your code precomputes files before attempting to return it. The solution is to really compute files on the fly, something like this:
pub fn contents(&self) -> Box<dyn Iterator<Item = (&OsString, &FileOrFolder)> + '_> {
let files = WalkDir::new(&self.full_path)
.max_depth(1)
.skip_hidden(false)
.follow_links(false)
.into_iter()
.filter_map (|entry| {
let ent = entry.unwrap;
if ent.file_type().is_file() {
if let Some(name) = ent.path().file_name() {
Some((
name.to_os_string(),
FileOrFolder::File(File {
name: name.to_os_string(),
size: ent.metadata().unwrap().len() as u128,
}),
))
} else None
} else None
});
self.contents
.iter()
.chain (files)
}
Since you haven't given us an MRE, I haven't tested the above, but I think it will fail because self.contents.iter() returns references, whereas files returns owned values. Fixing this requires changing the prototype of the function to return some form of owned values since files cannot be made to return references. I see two ways to do this:
Easiest is to make FileOrFolder clonable and get rid of the references in the prototype:
pub fn contents(&self) -> Box<dyn Iterator<Item = (OsString, FileOrFolder)> + '_> {
let files = ...;
self.contents
.iter()
.cloned()
.chain (files)
Or you can make a wrapper type similar to Cow than can hold either a reference or an owned value:
enum OwnedOrRef<'a, T> {
Owned (T),
Ref (&'a T),
}
pub fn contents(&self) -> Box<dyn Iterator<Item = (OwnedOrRef::<OsString>, OwnedOrRef::<FileOrFolder>)> + '_> {
let files = ...;
self.contents
.iter()
.map (|(k, v)| (OwnedOrRef::Ref (k), OwnedOrRef::Ref (v))
.chain (files
.map (|(k, v)| (OwnedOrRef::Owned (k),
OwnedOrRef::Owned (v)))
}
You can even use Cow if FileOrFolder can implement ToOwned.
I have an struct called Spire that contains some data (elements), and a cache of some result that can be calculated from that data. When elements changes, I want to be able to automatically update the cache (e.g. without the user of the struct having to manually call update_height in this case).
I'm trying to figure out how I can achieve that, or if there is a better way to do what I'm trying to do.
struct Spire {
elements: Vec<i32>,
height: i32,
}
impl Spire {
pub fn new(elements: Vec<i32>) -> Spire {
let mut out = Spire {
elements: elements,
height: 0,
};
out.update_height();
out
}
pub fn get_elems_mut(&mut self) -> &mut Vec<i32> {
&mut self.elements
}
pub fn update_height(&mut self) {
self.height = self.elements.iter().sum();
}
pub fn height(&self) -> i32 {
self.height
}
}
fn main() {
let mut spire = Spire::new(vec![1, 2, 3, 1]);
// Get a mutable reference to the internal elements
let spire_elems = spire.get_elems_mut();
// Do some stuff with the elements
spire_elems.pop();
spire_elems.push(7);
spire_elems.push(10);
// The compiler won't allow you to get height
// without dropping the mutable reference first
// dbg!(spire.height());
// When finished, drop the reference to the elements.
drop(spire_elems);
// I want to automatically run update_height() here somehow
dbg!(spire.height());
}
Playground
I am trying to find something with behavior like the Drop trait for mutable references.
There are at least two ways to tackle this problem. Instead of calling drop directly, you should put your code which does the mutation in a new scope so that the scoping rules will automatically be applied to them and drop will be called automatically for you:
fn main() {
let mut spire = Spire::new(vec![1, 2, 3, 1]);
{
let spire_elems = spire.get_elems_mut();
spire_elems.pop();
spire_elems.push(7);
spire_elems.push(10);
}
spire.update_height();
dbg!(spire.height());
}
If you compile this, it will work as expected. Generally speaking, if you have to call drop manually it usually means you are doing something that you shouldn't do.
That being said, the more interesting question is designing an API which is not leaking your abstraction. For example, you could protect your internal data structure representation by providing methods to manipulate it (which has several advantages, one of them is that you can freely change your mind later on what data structure you are using internally without effecting other parts of your code), e.g.
impl Spire {
pub fn push(&mut self, elem: i32) {
self.elements.push(elem);
self.update_internals();
}
}
This example invokes a private method called update_internals which takes care of your internal data consistency after each update.
If you only want to update the internal values when all the additions and removals have happened, then you should implement a finalising method which you have to call every time you finished modifying your Spire instance, e.g.
spire.pop();
spire.push(7);
spire.push(10);
spire.commit();
To achieve such a thing, you have at least another two options: you could do it like the above example or you could use a builder pattern where you are doing modifications throughout a series of calls which will then only have effect when you call the last finalising call on the chain. Something like:
spire.remove_last().add(7).add(10).finalise();
Another approach could be to have an internal flag (a simple bool would do) which is changed to true every time there is an insertion or deletion. Your height method could cache the calculated data internally (e.g. using some Cell type for interior mutability) and if the flag is true then it will recalculate the value and set the flag back to false. It will return the cached value on every subsequent call until you do another modification. Here's a possible implementation:
use std::cell::Cell;
struct Spire {
elements: Vec<i32>,
height: Cell<i32>,
updated: Cell<bool>,
}
impl Spire {
fn calc_height(elements: &[i32]) -> i32 {
elements.iter().sum()
}
pub fn new(elements: Vec<i32>) -> Self {
Self {
height: Cell::new(Self::calc_height(&elements)),
elements,
updated: Cell::new(false),
}
}
pub fn push(&mut self, elem: i32) {
self.updated.set(true);
self.elements.push(elem);
}
pub fn pop(&mut self) -> Option<i32> {
self.updated.set(true);
self.elements.pop()
}
pub fn height(&self) -> i32 {
if self.updated.get() {
self.height.set(Self::calc_height(&self.elements));
self.updated.set(false);
}
self.height.get()
}
}
fn main() {
let mut spire = Spire::new(vec![1, 2, 3, 1]);
spire.pop();
spire.push(7);
spire.push(10);
dbg!(spire.height());
}
If you don't mind borrowing self mutably in the height getter, then don't bother with the Cell, just update the values directly.
I know why Rust doesn't like my code. However, I don't know what would be the idiomatic Rust approach to the problem.
I'm a C# programmer, and while I feel I understand Rust's system, I think my "old" approach to some problems don't work in Rust at all.
This code reproduces the problem I'm having, and it probably doesn't look like idiomatic Rust (or maybe it doesn't even look good in C# as well):
//a "global" container for the elements and some extra data
struct Container {
elements: Vec<Element>,
global_contextual_data: i32,
//... more contextual data fields
}
impl Container {
//this just calculates whatever I need based on the contextual data
fn calculate_contextual_data(&self) -> i32 {
//This function will end up using the elements vector and the other fields as well,
//and will do some wacky maths with it.
//That's why I currently have the elements stored in the container
}
}
struct Element {
element_data: i32,
//other fields
}
impl Element {
//I need to take a mutable reference to update element_data,
//and a reference to the container to calculate something that needs
//this global contextual data... including the other elements, as previously stated
fn update_element_data(&mut self, some_data: i32, container: &Container) {
self.element_data *= some_data + container.calculate_contextual_data() //do whatever maths I need
}
}
fn main(){
//let it be mutable so I can assign the elements later
let mut container = Container {
elements: vec![],
global_contextual_data: 1
};
//build a vector of elements
let elements = vec![
Element {
element_data: 5
},
Element {
element_data: 7
}
];
//this works
container.elements = elements;
//and this works, but container is now borrowed as mutable
for elem in container.elements.iter_mut() {
elem.element_data += 1; //and while this works
let some_data = 2;
//i can't borrow it as immutable here and pass to the other function
elem.update_element_data(some_data, &container);
}
}
I understand why elem.update_element_data(some_data, &container); won't work: I'm already borrowing it as mutable when I call iter_mut. Maybe each element should have a reference to the container? But then wouldn't I have more opportunities to break at borrow-checking?
I don't think it's possible to bring my old approach to this new system. Maybe I need to rewrite the whole thing. Can someone point me to the right direction? I've just started programming in Rust, and while the ownership system is making some sort of sense to me, the code I should write "around" it is still not that clear.
I came across this question:
What's the Rust way to modify a structure within nested loops? which gave me insight into my problem.
I revisited the problem and boiled the problem down to the sharing of the vector by borrowing for writes and reads at the same time. This is just forbidden by Rust. I don't want to circumvent the borrow checker using unsafe. I was wondering, though, how much data should I copy?
My Element, which in reality is the entity of a game (I'm simulating a clicker game) has both mutable and immutable properties, which I broke apart.
struct Entity {
type: EntityType,
starting_price: f64,
...
...
status: Cell<EntityStatus>
}
Every time I need to change the status of an entity, I need to call get and set methods on the status field. EntityStatus derives Clone, Copy.
I could even put the fields directly on the struct and have them all be Cells but then it would be cumbersome to work with them (lots of calls to get and set), so I went for the more aesthetically pleasant approach.
By allowing myself to copy the status, edit and set it back, I could borrow the array immutably twice (.iter() instead of .iter_mut()).
I was afraid that the performance would be bad due to the copying, but in reality it was pretty good once I compiled with opt-level=3. If it gets problematic, I might change the fields to be Cells or come up with another approach.
Just do the computation outside:
#[derive(Debug)]
struct Container {
elements: Vec<Element>
}
impl Container {
fn compute(&self) -> i32 {
return 42;
}
fn len(&self) -> usize {
return self.elements.len();
}
fn at_mut(&mut self, index: usize) -> &mut Element {
return &mut self.elements[index];
}
}
#[derive(Debug)]
struct Element {
data: i32
}
impl Element {
fn update(&mut self, data: i32, computed_data: i32) {
self.data *= data + computed_data;
}
}
fn main() {
let mut container = Container {
elements: vec![Element {data: 1}, Element {data: 3}]
};
println!("{:?}", container);
for i in 0..container.len() {
let computed_data = container.compute();
container.at_mut(i).update(2, computed_data);
}
println!("{:?}", container);
}
Another option is to add an update_element to your container:
#[derive(Debug)]
struct Container {
elements: Vec<Element>
}
impl Container {
fn compute(&self) -> i32 {
let sum = self.elements.iter().map(|e| {e.data}).reduce(|a, b| {a + b});
return sum.unwrap_or(0);
}
fn len(&self) -> usize {
return self.elements.len();
}
fn at_mut(&mut self, index: usize) -> &mut Element {
return &mut self.elements[index];
}
fn update_element(&mut self, index: usize, data: i32) {
let computed_data = self.compute();
self.at_mut(index).update(data, computed_data);
}
}
#[derive(Debug)]
struct Element {
data: i32
}
impl Element {
fn update(&mut self, data: i32, computed_data: i32) {
self.data *= data + computed_data;
}
}
fn main() {
let mut container = Container {
elements: vec![Element {data: 1}, Element {data: 3}]
};
println!("{:?}", container);
for i in 0..container.len() {
let computed_data = container.compute();
container.at_mut(i).update(2, computed_data);
}
println!("{:?}", container);
for i in 0..container.len() {
container.update_element(i, 2);
}
println!("{:?}", container);
}
Try it!