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 }
}
I have a recursive structure, where field of a structure is a reference to other struct of same type:
use std::collections::HashMap;
pub struct RecursiveStruct<'a> {
outer: Option<Box<&'a RecursiveStruct<'a>>>,
dict: HashMap<u32, String>
}
With this structure I also have couple of methods such as constructor, method which adds (k,v) pair to calee's field and a getter:
impl<'a> RecursiveStruct<'a> {
pub fn new(outer: Option<Box<&'a RecursiveStruct<'a>>>) -> Self {
let dict: HashMap<u32, String> = HashMap::new();
RecursiveStruct { outer, dict }
}
// searches for value corresponding to key in all struct layers
pub fn get(&self, key: u32) -> Result<String, ()> {
let item = self.dict.get(&key);
match item {
Some(x) => Ok(x.clone()),
None => {
match &self.outer {
Some(x) => x.get(key),
None => Err(())
}
}
}
}
// adds (key, val) to "innermost" instance of struct
pub fn add(&mut self, key:u32, val: String) {
self.dict.insert(key, val);
}
}
These methods work fine, but when I try to add a method, which tries to modify dict field in any of the inner layers, I get cannot borrow '***x' as mutable, as it is behind a '&' reference error.
pub fn re_assign(&mut self, key: u32, val: String) {
if self.dict.contains_key(&key) {
self.dict.insert(key, val);
} else {
match &mut self.outer {
Some(x) => x.re_assign(key, val.clone()),
None => println!("Such key couldn't be found!"),
};
}
}
Here is the link to playground.
You are using a &, but want a &mut, rust references are immutable by default:
Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=be82b8ba01dff60e106af9e59df8228e
use std::collections::HashMap;
pub struct RecursiveStruct<'a> {
outer: Option<Box<&'a mut RecursiveStruct<'a>>>,
dict: HashMap<u32, String>
}
impl<'a> RecursiveStruct<'a> {
pub fn new(outer: Option<Box<&'a mut RecursiveStruct<'a>>>) -> Self {
let dict: HashMap<u32, String> = HashMap::new();
RecursiveStruct { outer, dict }
}
pub fn get(&self, key: u32) -> Result<String, ()> {
let item = self.dict.get(&key);
match item {
Some(x) => Ok(x.clone()),
None => {
match &self.outer {
Some(x) => x.get(key),
None => Err(())
}
}
}
}
pub fn re_assign(&mut self, key: u32, val: String) {
if self.dict.contains_key(&key) {
self.dict.insert(key, val);
} else {
match &mut self.outer {
Some(x) => x.re_assign(key, val.clone()),
None => println!("Such key couldn't be found!"),
};
}
}
pub fn add(&mut self, key:u32, val: String) {
self.dict.insert(key, val);
}
}
fn main() {
// instantiate "outer" struct and set its field
let mut S = RecursiveStruct::new(None);
S.add(42, "Answer to the universe!".to_string());
// instantiate "inner" struct
let mut S1 = RecursiveStruct::new(Some(Box::new(&mut S)));
println!("{}", S1.get(42).unwrap()); // get the field of outer struct
// modify the field of outer struct
S1.re_assign(42, "The answer has been changed.".to_string());
println!("{}", S1.get(42).unwrap());
}
I have a Vec<dyn MyObj> and the first implementation of MyObj contained in the Vec can contains something that refers to a second implementation of MyObj contained in the same Vec.
I'd like that the first implementation can mutate the second implementation.
Here is my first idea:
use std::{rc::{Rc, Weak}, cell::RefCell};
trait MyObj {
fn f(&mut self);
}
type CRef = Weak<RefCell<Container>>;
struct Container {
list: Vec<Box<dyn MyObj>>,
this: CRef,
}
impl Container {
fn new() -> Rc<RefCell<Self>> {
let res = Rc::new(RefCell::new(Self {
list: vec![],
this: Weak::new(),
}));
{
let this = Rc::downgrade(&res);
let mut ref_on_res = res.borrow_mut();
ref_on_res.this = this;
}
res
}
fn register(&mut self, v: impl MyObj + 'static) -> ObjRef {
let index = self.list.len();
self.list.push(Box::new(v));
ObjRef::new(self.this.clone(), index)
}
fn get(&mut self, index: usize) -> &mut (dyn MyObj + 'static) {
let elt = &mut self.list[index];
Box::as_mut(elt)
}
}
struct ObjRef {
c: CRef,
i: usize,
}
impl ObjRef {
fn new(c: CRef, i: usize) -> Self {
Self { c, i }
}
}
impl MyObj for ObjRef {
fn f(&mut self) {
let i = self.i;
self.c.upgrade().map(|c| c.borrow_mut().get(i).f());
}
}
struct A {
r: ObjRef,
}
// First implementation
impl A {
fn new(r: ObjRef) -> A {
A { r }
}
}
impl MyObj for A {
fn f(&mut self) {
self.r.f();
}
}
// Second implementation
struct B(usize);
impl MyObj for B {
fn f(&mut self) {
self.0 += 1;
println!("B({})", self.0);
}
}
fn main() {
let c = Container::new();
let mut r = {
let b = c.borrow_mut().register(B(100));
c.borrow_mut().register(A::new(b))
};
r.f(); // -> Panic: already borrowed: BorrowMutError
}
Obviously, it panics and i understand why but i have no idea to fix this problem.
Have you any idea to do this kind of modification ?
I can understand borrowing/ownership concepts in Rust, but I have no idea how to work around this case:
use std::collections::{HashMap, HashSet};
struct Val {
t: HashMap<u16, u16>,
l: HashSet<u16>,
}
impl Val {
fn new() -> Val {
Val {
t: HashMap::new(),
l: HashSet::new(),
}
}
fn set(&mut self, k: u16, v: u16) {
self.t.insert(k, v);
self.l.insert(v);
}
fn remove(&mut self, v: &u16) -> bool {
self.l.remove(v)
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
Some(r) => self.remove(r),
}
}
}
fn main() {
let mut v = Val::new();
v.set(123, 100);
v.set(100, 1234);
println!("Size before: {}", v.l.len());
println!("Work: {}", v.do_work(123));
println!("Size after: {}", v.l.len());
}
playground
The compiler has the error:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:28:24
|
26 | match self.t.get(&v) {
| ------ immutable borrow occurs here
27 | None => false,
28 | Some(r) => self.remove(r),
| ^^^^^------^^^
| | |
| | immutable borrow later used by call
| mutable borrow occurs here
I don't understand why I can't mutate in the match arm when I did a get (read value) before; the self.t.get is finished when the mutation via remove begins.
Is this due to scope of the result (Option<&u16>) returned by the get? It's true that the lifetime of the result has a scope inside the match expression, but this design-pattern is used very often (mutate in a match expression).
How do I work around the error?
The declaration of function HashMap::<K,V>::get() is, a bit simplified:
pub fn get<'s>(&'s self, k: &K) -> Option<&'s V>
This means that it returns an optional reference to the contained value, not the value itself. Since the returned reference points to a value inside the map, it actually borrows the map, that is, you cannot mutate the map while this reference exists. This restriction is there to protect you, what would happen if you remove this value while the reference is still alive?
So when you write:
match self.t.get(&v) {
None => false,
//r: &u16
Some(r) => self.remove(r)
}
the captured r is of type &u16 and its lifetime is that of self.t, that is, it is borrowing it. Thus you cannot get a mutable reference to self, that is needed to call remove.
The simplest solution for your problem is the clone() solves every lifetime issue pattern. Since your values are of type u16, that is Copy, it is actually trivial:
match self.t.get(&v) {
None => false,
//r: u16
Some(&r) => self.remove(&r)
}
Now r is actually of type u16 so it borrows nothing and you can mutate self at will.
If your key/value types weren't Copy you could try and clone them, if you are willing to pay for that. If not, there is still another option as your remove() function does not modify the HashMap but an unrelated HashSet. You can still mutate that set if you take care not to reborrow self:
fn remove2(v: &u16, l: &mut HashSet<u16>) -> bool {
l.remove(v)
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
//selt.t is borrowed, now we mut-borrow self.l, no problem
Some(r) => Self::remove2(r, &mut self.l)
}
}
You are trying to remove value from HashMap by using value you get, not key.
Only line 26 is changed Some(_) => self.remove(&v)
This will work:
use std::collections::HashMap;
struct Val {
t: HashMap<u16, u16>
}
impl Val {
fn new() -> Val {
Val { t: HashMap::new() }
}
fn set(&mut self, k: u16, v: u16) {
self.t.insert(k, v);
}
fn remove(&mut self, v: &u16) -> bool {
match self.t.remove(v) {
None => false,
_ => true,
}
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
Some(_) => self.remove(&v)
}
}
}
fn main() {
let mut v = Val::new();
v.set(123, 100);
v.set(1100, 1234);
println!("Size before: {}", v.t.len());
println!("Work: {}", v.do_work(123));
println!("Size after: {}", v.t.len());
}
play.rust
It seems that the following solution is good for primitive types like here u16. For other types, the ownership is moved.
use std::collections::HashMap;
struct Val {
t: HashMap<u16, u16>,
}
impl Val {
fn new() -> Val {
Val { t: HashMap::new() }
}
fn set(&mut self, k: u16, v: u16) {
self.t.insert(k, v);
}
fn remove(&mut self, v: &u16) -> bool {
match self.t.remove(v) {
None => false,
_ => true,
}
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
Some(&v) => self.remove(&v)
}
}
}
fn main() {
let mut v = Val::new();
v.set(123, 100);
v.set(100, 1234);
println!("Size before: {}", v.t.len());
println!("Work: {}", v.do_work(123));
println!("Size after: {}", v.t.len());
}
For other types, we must clone the value:
use std::collections::{HashMap, HashSet};
#[derive(Debug)]
struct Val {
t: HashMap<String, String>,
l: HashSet<String>
}
impl Val {
fn new() -> Val {
Val { t: HashMap::new(), l: HashSet::new() }
}
fn set(&mut self, k: String, v: String) {
self.l.insert(v.clone());
self.t.insert(k, v);
}
fn remove(&mut self, v: &String) -> bool {
self.l.remove(v)
}
fn do_work(&mut self, i: &String) -> bool {
match self.t.get(i) {
None => false,
Some(v) => {
let x = v.clone();
self.remove(&x)
}
}
}
fn do_task(&mut self, i: &String) -> bool {
match self.t.get(i) {
None => false,
Some(v) => self.l.insert(v.clone())
}
}
}
fn main() {
let mut v = Val::new();
v.set("AA".to_string(), "BB".to_string());
v.set("BB".to_string(), "CC".to_string());
println!("Start: {:#?}", v);
println!("Size before: {}", v.l.len());
println!("Work: {}", v.do_work(&"AA".to_string()));
println!("Size after: {}", v.l.len());
println!("After: {:#?}", v);
println!("Task [Exist]: {}", v.do_task(&"BB".to_string()));
println!("Task [New]: {}", v.do_task(&"AA".to_string()));
println!("End: {:#?}", v);
}
But i'd like a solution that has no allocation
I need to initialize an item (fn init(&mut self) -> Option<&Error>), and use it if there's no errors.
pub fn add(&mut self, mut m: Box<Item>) {
if let None = m.init() {
self.items.push(m);
}
}
This works unless I need to check the error if there's any:
pub fn add(&mut self, mut m: Box<Item>) {
if let Some(e) = m.init() {
//process error
} else {
self.items.push(m); //won't compile, m is borrowed
}
}
Fair. Need to use RefCell. However, this
pub fn add(&mut self, mut m: Box<Item>) {
let rc = RefCell::new(m);
if let Some(e) = rc.borrow_mut().init() {
//process error
} else {
self.items.push(rc.borrow_mut())
}
}
ends with weird
error: `rc` does not live long enough
if let Some(e) = rc.borrow_mut().init() {
^~
note: reference must be valid for the destruction scope surrounding block at 75:60...
pub fn add_module(&mut self, mut m: Box<RuntimeModule>) {
^
note: ...but borrowed value is only valid for the block suffix following statement 0 at 76:30
let rc = RefCell::new(m);
I tried nearly everything: plain box, Rc'ed box, RefCell'ed box, Rc'ed RefCell. Tried to adapt this answer to my case. No use.
Complete example:
use std::cell::RefCell;
use std::error::Error;
trait Item {
fn init(&mut self) -> Option<&Error>;
}
struct ItemImpl {}
impl Item for ItemImpl {
fn init(&mut self) -> Option<&Error> {
None
}
}
//===========================================
struct Storage {
items: Vec<Box<Item>>,
}
impl Storage {
fn new() -> Storage {
Storage{
items: Vec::new(),
}
}
fn add(&mut self, mut m: Box<Item>) {
let rc = RefCell::new(m);
if let Some(e) = rc.borrow_mut().init() {
//process error
} else {
self.items.push(*rc.borrow_mut())
}
}
}
fn main() {
let mut s = Storage::new();
let mut i = Box::new(ItemImpl{});
s.add(i);
}
(Playground)
UPD: As suggested, this is a "family" of mistakes like I did, it is well explained here. However my case has easier solution.
As krdln suggested, the simplest way to work around this is to return in the if block and thus scope the borrow:
fn add(&mut self, mut m: Box<Item>) {
if let Some(e) = m.init() {
//process error
return;
}
self.items.push(m);
}