I want to extend the Iterator trait with some convenience function. For example
trait BetterIterator: Iterator {
fn skip_bad(&mut self);
}
This can be achieved like this:
struct Iter {}
impl Iterator for Iter {
type Item = ();
fn next(&mut self) -> Option<()> { None }
}
impl BetterIterator for Iter {
fn skip_bad(&mut self) {}
}
fn make_iter() -> Box<dyn BetterIterator<Item=()>> {
Box::new( Iter {} )
}
fn main()
{
let mut iter = make_iter();
iter.skip_bad();
for _item in iter {
// ...
}
}
What is unusual, here, is the dynamic dispatch in make_iter.
Now, it would be much nicer if skip_bad could be chained, e.g.
for _item in make_iter().skip_bad() {
// ...
}
That means BetterIterator becomes
trait BetterIterator: Iterator {
fn skip_bad(&mut self) -> &mut Self;
}
impl BetterIterator for Iter {
fn skip_bad(&mut self) -> &mut Self { self }
}
But then the compiler complains "the trait BetterIterator cannot be made into an object".
Is it correct that the violated rule in Object Safety is "Dispatchable functions require: ...Be a method that does not use Self except in the type of the receiver."?
There is no way out of this, is there?
If dynamic dispatch is your goal you can return a mutable reference to a dyn BetterIterator instead.
trait BetterIterator: Iterator {
fn skip_bad(&mut self) -> &mut dyn BetterIterator<Item = Self::Item>;
}
impl BetterIterator for Iter {
fn skip_bad(&mut self) -> &mut dyn BetterIterator<Item = Self::Item> { self }
}
Related
For example, this works:
pub struct SquareVecIter<'a> {
current: f64,
iter: core::slice::Iter<'a, f64>,
}
pub fn square_iter<'a>(vec: &'a Vec<f64>) -> SquareVecIter<'a> {
SquareVecIter {
current: 0.0,
iter: vec.iter(),
}
}
impl<'a> Iterator for SquareVecIter<'a> {
type Item = f64;
fn next(&mut self) -> Option<Self::Item> {
if let Some(next) = self.iter.next() {
self.current = next * next;
Some(self.current)
} else {
None
}
}
}
// switch to test module
#[cfg(test)]
mod tests_2 {
use super::*;
#[test]
fn test_square_vec() {
let vec = vec![1.0, 2.0];
let mut iter = square_iter(&vec);
assert_eq!(iter.next(), Some(1.0));
assert_eq!(iter.next(), Some(4.0));
assert_eq!(iter.next(), None);
}
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=531edc40dcca4a79d11af3cbd29943b7
But if I have to return references to self.current then I can't get the lifetimes to work.
Yes.
An Iterator cannot yield elements that reference itself simply due to how the trait is designed (search "lending iterator" for more info). So even if you wanted to return Some(&self.current) and deal with the implications therein, you could not.
Returning an f64 (non-reference) is perfectly acceptable and would be expected because this is a kind of generative iterator. And you wouldn't need to store current at all:
pub struct SquareVecIter<'a> {
iter: core::slice::Iter<'a, f64>,
}
pub fn square_iter<'a>(vec: &'a Vec<f64>) -> SquareVecIter<'a> {
SquareVecIter {
iter: vec.iter(),
}
}
impl<'a> Iterator for SquareVecIter<'a> {
type Item = f64;
fn next(&mut self) -> Option<Self::Item> {
if let Some(next) = self.iter.next() {
Some(next * next)
} else {
None
}
}
}
For an example of this in the standard library, look at the Chars iterator for getting characters of a string. It keeps a reference to the original str, but it yields owned chars and not references.
What #kmdreko says, of course.
I just wanted to add a couple of nitpicks:
The pattern of the if let Some(...) = ... {Some} else {None} is so common that it made its way into the standard library as the .map function.
Taking a &Vec<f64> is an antipattern. Use &[f64] instead. It is more general without any drawbacks.
All of your lifetime annotations (except of the one in the struct definition) can be derived automatically, so you can simply omit them.
pub struct SquareVecIter<'a> {
iter: core::slice::Iter<'a, f64>,
}
pub fn square_iter(vec: &[f64]) -> SquareVecIter {
SquareVecIter { iter: vec.iter() }
}
impl Iterator for SquareVecIter<'_> {
type Item = f64;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|next| next * next)
}
}
I have a trait that I own:
trait Reducer {
fn reduce(&self) -> Res;
}
I want to implement for the following cases:
struct MyStruct {... fields ...}
impl Reducer for Vec<MyStruct> {
fn reduce(&self) -> Res { ... some implementation ... }
}
I want to get for as cheap as possible (not duplicating code etc.) for the refs of objects in Vec:
for instance:
// I want this please:
impl Reducer for Vec<&MyStruct> {
// it's the same implementation as before
}
How should I change my impl signature to satisfy both cases?
Using the Borrow trait you can generalize for all types that can be borrowed as a &MyStruct (which in particular includes MyStruct and &MyStruct):
use std::borrow::Borrow;
trait Reducer {
fn reduce(&self) -> Res;
}
struct MyStruct;
struct Res;
impl<T: Borrow<MyStruct>> Reducer for Vec<T> {
fn reduce(&self) -> Res {
for t in self {
let _t: &MyStruct = t.borrow();
// do something with `_t`
}
Res
}
}
fn main() {
let v: Vec<MyStruct> = vec![];
let v_ref: Vec<&MyStruct> = vec![];
// fully qualified because it gets mangled with `Iterator::reduce` otherwise.
Reducer::reduce(&v);
Reducer::reduce(&v_ref);
}
If your reducer only needs to iterate over the items in the Vec, then there is no difference between Vec<T> and Vec<&T> because both can easily produce an iterator over &T. For example:
// actual implementation
fn reduce_it<'a>(_items: impl Iterator<Item = &'a MyStruct>) -> Res {
todo!()
}
impl Reducer for Vec<MyStruct> {
fn reduce(&self) -> Res {
reduce_it(self.iter())
}
}
impl Reducer for Vec<&MyStruct> {
fn reduce(&self) -> Res {
reduce_it(self.iter().copied())
}
}
Playground
Is there a cleaner way to do this?
for i in collection.iter().enumerate().map(|(i, _)| i) {...}
In other words I'm looking for a method like enumerate but which only gives the indices, not the values. Something like
for i in collection.iter().indices() {...}
Does such a method exist?
I want to chain a bunch of other methods but I don't want to type |(i, _)| in each closure, I want to just type |i|
[...]
Does such a method exist?
No, but you can write an extension trait that provides one (playground):
trait IndicesExt<I> {
fn indices(self) -> Indices<I>;
}
struct Indices<I> {
next: usize,
iter: I,
}
impl<I: Iterator> IndicesExt<I> for I {
fn indices(self) -> Indices<I> {
Indices {
next: 0,
iter: self,
}
}
}
impl<I: Iterator> Iterator for Indices<I> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
if let Some(_) = self.iter.next() {
let current = self.next;
self.next += 1;
Some(current)
} else {
None
}
}
}
The implementation can be simplified by reusing the Enumerate iterator returned by Iterator::enumerate() (playground):
struct Indices<I>(std::iter::Enumerate<I>);
impl<I: Iterator> IndicesExt<I> for I {
fn indices(self) -> Indices<I> {
Indices(self.enumerate())
}
}
impl<I: Iterator> Iterator for Indices<I> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
self.0.next().map(|(idx, _)| idx)
}
}
pub struct ForesterViewModel {
m_tree_lines: Arc<Mutex<Vec<TreeLine>>>,
}
impl ForesterViewModel {
pub fn new() -> ForesterViewModel {
ForesterViewModel {
m_tree_lines: Arc::new(Mutex::new(vec![])),
}
}
pub fn get_the_forest(&mut self) -> &mut Vec<TreeLine> {
???????????????????????????????
}
}
I need help writing the get_the_forest function. I've tried many various things but they all return compilation errors. I need to return a mutable reference to Vec<TreeLine> which is wrapped behind an Arc and a Mutex in self.m_tree_lines.
There is no way of doing this.
You create a concrete MutexGuard object that releases the mutex when it dropped when you call lock; you cannot move a reference out of the scope that contains the guard:
pub fn as_mut(&mut self) -> &Whatever {
let mut guard = self.data.lock().unwrap();
Ok(guard.deref())
drop(guard) // <--- implicitly added here, which would invalidate the ref
}
You also cannot return both the mutex guard and a reference, for more complex reasons (basically rust cannot express that), for the same reason it cannot have a reference and an object in a single structure; see the discussion on Why can't I store a value and a reference to that value in the same struct?
...so basically your best bet is one of two things:
/// Return the mutex guard itself
pub fn get_the_forest(&mut self) -> Result<MutexGuard<Vec<TreeLine>>, TreeLockError> {
Ok(self.m_tree_lines.lock()?)
}
/// Pass a function in, which patches the mutable internal value
pub fn patch_forest(&mut self, patch: impl Fn(&mut Vec<TreeLine>)) -> Result<(), TreeLockError>{
let mut guard = self.m_tree_lines.lock()?;
patch(&mut guard); // <-- patch happens while guard is still alive
Ok(())
}
Full code:
use std::sync::{Arc, Mutex, MutexGuard};
use std::sync::PoisonError;
use std::error::Error;
use std::fmt;
use std::fmt::Formatter;
use std::ops::Deref;
#[derive(Debug, Copy, Clone)]
pub enum TreeLockError {
FailedToLock
}
impl Error for TreeLockError {}
impl fmt::Display for TreeLockError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl<T> From<PoisonError<T>> for TreeLockError {
fn from(_: PoisonError<T>) -> Self {
TreeLockError::FailedToLock
}
}
// ---
#[derive(Debug)]
pub struct TreeLine {
pub value: &'static str
}
pub struct ForesterViewModel {
m_tree_lines: Arc<Mutex<Vec<TreeLine>>>,
}
impl ForesterViewModel {
pub fn new() -> ForesterViewModel {
ForesterViewModel {
m_tree_lines: Arc::new(Mutex::new(vec![])),
}
}
pub fn get_the_forest(&mut self) -> Result<MutexGuard<Vec<TreeLine>>, TreeLockError> {
Ok(self.m_tree_lines.lock()?)
}
pub fn patch_forest(&mut self, patch: impl Fn(&mut Vec<TreeLine>)) -> Result<(), TreeLockError>{
let mut guard = self.m_tree_lines.lock()?;
patch(&mut guard);
Ok(())
}
}
fn main() -> Result<(), Box<dyn Error>> {
let mut vm = ForesterViewModel::new();
{
let mut trees = vm.get_the_forest()?;
trees.push(TreeLine{ value: "one"});
trees.push(TreeLine{ value: "two"});
} // <--- Drop the mutable reference here so you can get it again later
// Patch
vm.patch_forest(|trees| {
trees.push(TreeLine{ value: "three"});
});
// ...
let trees = vm.get_the_forest()?;
println!("{:?}", trees.deref());
Ok(())
}
I have a Vec<Rc<RefCell<MyStruct>>> member on a struct and I have an external library function that expects to be handed an Iterator with an Item that is a &'a mut dyn LibTrait which I have as a member inside MyStruct. I can't figure out how to get a raw &mut from out of the Rc<RefCell<MyStruct>> in my iterator even though I know the Vec member that holds it will stick around for longer than either the iterator or the function that gets passed the iterator.
The library looks like this:
struct Lib {}
trait LibTrait {
fn run(&mut self);
}
impl Lib {
pub fn lib_func<'a, Iter>(&mut self, trait_iter: Iter)
where
Iter: Iterator<Item = &'a mut dyn LibTrait>,
{
...
}
}
Here's my latest attempt where I tried to create a temp Vec to hold RefMut's to all the MyStructs so that those refs are owned for the whole time that the &mut would be inside the iterator and lib function. (This code complains about "cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements".)
struct TraitImpl {
dummy: f32,
}
impl LibTrait for TraitImpl {
fn run(&mut self) {
self.dummy += 1.0;
}
}
struct MyStruct {
my_impl: TraitImpl,
num: f32,
}
type MutStructSlice<'a> = &'a mut [&'a mut MyStruct];
struct TraitIterator<'a> {
my_structs: MutStructSlice<'a>,
index: usize,
}
impl<'a> TraitIterator<'a> {
fn new(my_structs: MutStructSlice<'a>) -> Self {
Self {
my_structs,
index: 0,
}
}
}
impl<'a> Iterator for TraitIterator<'a> {
type Item = &'a mut dyn LibTrait;
fn next(&mut self) -> Option<&'a mut dyn LibTrait> {
if self.index >= self.my_structs.len() {
return None;
}
Some(&mut self.my_structs[self.index].my_impl)
}
}
struct Data {
data: Vec<Rc<RefCell<MyStruct>>>,
lib: Lib,
}
impl Data {
fn do_stuff(&mut self) {
let mut struct_refs: Vec<RefMut<MyStruct>> = self
.data
.iter_mut()
.map(|s_rc| s_rc.borrow_mut())
.collect();
let mut structs_raw_refs: Vec<&mut MyStruct> =
struct_refs.iter_mut().map(|s_ref| &mut **s_ref).collect();
self.lib.lib_func(TraitIterator::new(&mut structs_raw_refs));
}
}
Here's the playground
Is there some way around this given that I can't change the library and I need to have Rc<RefCell<>>'s to the data?
I think you're overcomplicating this. You don't need a custom iterator, you can do this with .map():
fn do_stuff(&mut self) {
let mut struct_refs: Vec<RefMut<MyStruct>> = self.data
.iter_mut()
.map(|s_rc| s_rc.borrow_mut())
.collect();
self.lib.lib_func(struct_refs.iter_mut().map(|s_ref| &mut s_ref.my_impl as &mut dyn LibTrait));
}
You get the error you did because implementing Iterator for &mut T is inherently unsafe. See How to implement Iterator yielding mutable references.