This question already has answers here:
What is the difference between iter and into_iter?
(5 answers)
Closed last month.
I'm trying to find and change a specific item in an iterator like this:
struct ItemType {
name: &'static str,
value: i32
}
struct OuterType {
list: Vec<ItemType>
}
impl OuterType {
pub fn setByName(
self: &mut Self,
name: &str
) -> Result<(), String> {
match self.list.iter().find(|item| item.name == name) {
Some(item_found) => {
item_found.value = 1;
},
None => {
return Err(format!("unrecognized item name (was \"{}\")", name));
}
}
Ok(())
}
}
But this does not compile because of several reasons, some of which:
no Copy trait (don't want to change a copy, I want to change the item in-place);
not borrowed, add & (does not help);
not mutable, add mut (does not help);
cannot assign to item_found.value which is behind a &;
at some point it says & can PROBABLY be removed... (WHAT?);
those errors are cyclic, I'm ping-pong-ing between them with no exit.
I've also tried to .find(|&item| ...).
What is going on? Don't I get to own the value returned by find()? And how am I supposed to change item_found.value? It's just an integer in a struct which is one of several in a vector I get the iterator for.
Just use iter_mut instead of iter when you need to mutate the value:
match self.list.iter_mut().find(...) {...}
Playground
Related
This question already has an answer here:
Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?
(1 answer)
Closed 3 months ago.
I am implementing a cache which tries a lookup in a table, if that fails it tries a simple method to get the value, and if that fails, it goes and computes multiple new entries in the cache. The Entry system seems specifically designed for the first half of this, but I cannot get the borrow checker to allow me to complete the last half.
use std::collections::HashMap;
fn main() {
let mut cache = Cache { cache: HashMap::new() };
println!("{}", cache.get_from_cache(10));
}
struct Cache {
cache: HashMap<u32, String>
}
impl Cache {
fn get_from_cache<'a>(&'a mut self, i: u32) -> &'a String {
match self.cache.entry(i) {
std::collections::hash_map::Entry::Occupied(entry) => return entry.into_mut(),
std::collections::hash_map::Entry::Vacant(entry) => {
// Some values have an easy way to be computed...
if i == 5 {
return entry.insert("my string".to_string())
}
}
}
// Neither look-up method succeeded, so we 'compute' values one-by-one
for j in 1..=i {
self.cache.insert(j, "another string".to_string()); // Borrow checker fails here
}
self.cache.get(&i).unwrap()
}
}
The problem is that the Entry from self.cache.entry(i) borrows self.cache for the entire lifetime 'a even though I no longer need it at the point that I attempt to do self.cache.insert.
One solution to this (I think) would be if there were a way to turn my reference to the Entry into a reference to its HashMap and then insert through that reference. However, I see no way to do this with the entry interface. Is there some way to achieve this? Or to otherwise satisfy the borrow checker?
This is easily fixed by separating inserting values from returning the final result. You can first make sure the value is in the cache or insert it with some strategy if not, and then return the new value (now guaranteed to be in the HashMap):
fn get_from_cache<'a>(&'a mut self, i: u32) -> &'a String {
// handle inserting the value if necessary:
match self.cache.entry(i) {
std::collections::hash_map::Entry::Occupied(entry) => (),
// Some values have an easy way to be computed...
std::collections::hash_map::Entry::Vacant(entry) if i == 5 => {
entry.insert("my string".to_string());
}
// ... others aren't
std::collections::hash_map::Entry::Vacant(entry) => {
for j in 1..=i {
self.cache.insert(j, "another string".to_string());
}
}
}
// The value is now definitely in `self.cache` so we can return a reference to it
&self.cache[&i]
}
This question already has answers here:
Obtain a reference from a RefCell<Option<Rc<T>>> in Rust
(1 answer)
How do I borrow a RefCell<HashMap>, find a key, and return a reference to the result? [duplicate]
(1 answer)
How do I return a reference to something inside a RefCell without breaking encapsulation?
(3 answers)
Closed 12 months ago.
Assume following code
pub struct Universe {
components: Rc<RefCell<Vec<Component>>>,
active_component: Rc<RefCell<Option<usize>>>,
}
I would like to introduce a convenience method that returns a mutable reference to the active component, e.g.
fn get_active_component(&mut self) -> Option<&mut Component> {
if let Some(active_component_idx) = self.active_component.borrow().as_ref() {
let i = *active_component_idx;
return self.components.borrow_mut().get_mut(i);
}
Option::None
}
which results in error
145 | return self.components.borrow_mut().get_mut(i);
| ----------------------------^^^^^^^^^^^
| |
| returns a reference to data owned by the current function
| temporary value created here
I do understand the error. The borrow_mut() creates a temporary variable which goes out of scope after the function returns. But I have absolutely no idea how you would realize such a method in rust apart from always inlining the code.
The standard way would be to mimic what RefCell does -- return a proxy struct wrapping the RefMut from .borrow_mut() and containing the vector index, implementing Deref and DerefMut.
pub struct ComponentHandle<'a> {
vecref: RefMut<'a, Vec<Component>>,
index: usize,
}
impl Deref for ComponentHandle<'_> {
type Target = Component;
fn deref(&self) -> &Component {
// SAFETY: We already verified the index is valid, RefCell won't
// dispense another mutable reference while we hold the RefMut, and we
// don't modify the vector's length, so we know this index is valid.
unsafe { self.vecref.get_unchecked(self.index) }
}
}
impl DerefMut for ComponentHandle<'_> {
fn deref_mut(&mut self) -> &mut Component {
// SAFETY: We already verified the index is valid, RefCell won't
// dispense another mutable reference while we hold the RefMut, and we
// don't modify the vector's length, so we know this index is valid.
unsafe { self.vecref.get_unchecked_mut(self.index) }
}
}
impl Universe {
fn get_active_component(&mut self) -> Option<ComponentHandle<'_>> {
if let Some(active_component_idx) = self.active_component.borrow().as_ref() {
let vecref = self.components.borrow_mut();
let index = *active_component_idx;
if index < vecref.len() {
return Some(ComponentHandle { vecref, index });
}
}
None
}
}
Alternatively, this function could accept a closure to invoke, passing it the bare reference. This is simpler to code, though less idiomatic:
fn get_active_component<F>(&mut self, f: F)
where F: FnOnce(Option<&mut Component>)
{
if let Some(active_component_idx) = self.active_component.borrow().as_ref() {
let i = *active_component_idx;
f(self.components.borrow_mut().get_mut(i));
} else {
f(None);
}
}
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.
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.
This question already has answers here:
How can I swap in a new value for a field in a mutable reference to a structure?
(2 answers)
Closed 4 years ago.
(Following "cannot move out of borrowed content" when replacing a struct field)
I have a third-party API where one struct have a method that consumes the instance and returns a new instance; I want to wrap this API in my own wrapper and abstract away the detail that the struct is consumed in the operation.
This example explains what I'm trying to achieve:
// Third-party API
struct Item {
x: u32,
}
impl Item {
pub fn increment(self, amount: u32) -> Self {
Item { x: self.x + amount }
}
}
// My API
struct Container {
item: Item,
}
impl Container {
pub fn increment_item(&mut self, amount: u32) {
// This line causes "cannot move out of borrowed content" but this is exactly what I want to do
self.item = self.item.increment(amount);
}
}
While now I understand the error I'm wondering how can I implement this without taking ownership of self inside Container::increment_item.
Proposed solutions:
Change Item::increment to take &mut self instead of self: I can't, Item::increment comes from a crate.
Use mem::replace (from here): Unfortunately constructing an Item instance it's not that easy, and to be honest I don't completely understand how the mem::replace solutions works.
Change Container::increment_item to take self instead of &mut self: I don't want to consume the Container instance in the process, I'm trying to design my wrapper to be as ergonomic as possible and abstract away completely the fact that Item must be consumed when changing it.
Some ideas on how to do it? Or am I trying an impossible design in Rust?
The simplest way is to use an Option:
use take to take ownership of the item,
then assign back Some(...).
If a panic occurs while the Option is empty, this is perfectly safe. No double-destruction occurs, and the container can even remain usable if you so desire.
Or in code:
// Third-party API
struct Item {
x: u32,
}
impl Item {
pub fn increment(self, amount: u32) -> Self {
Item { x: self.x + amount }
}
}
// My API
struct Container {
item: Option<Item>,
}
impl Container {
pub fn increment_item(&mut self, amount: u32) {
let item = self.item.take().unwrap();
self.item = Some(self.item.increment(amount));
}
}