I have an Option<T> that is shared by several structures and that must be mutable. I'm using a RefCell since, as I understand, it is the tool for that job. How do I access (and alter) the content of that Option<T> ?
I tried the following:
use std::cell::RefCell;
#[derive(Debug)]
struct S {
val: i32
}
fn main() {
let rc: RefCell<Option<S>> = RefCell::new(Some(S{val: 0}));
if let Some(ref mut s2) = rc.borrow_mut() {
s2.val += 1;
}
println!("{:?}", rc);
}
But the compiler won't let me do it:
error[E0308]: mismatched types
--> <anon>:10:12
|
10 | if let Some(ref mut s2) = rc.borrow_mut() {
| ^^^^^^^^^^^^^^^^ expected struct `std::cell::RefMut`, found enum `std::option::Option`
|
= note: expected type `std::cell::RefMut<'_, std::option::Option<S>, >`
found type `std::option::Option<_>`
When you borrow_mut the RefCell, you get a RefMut, as the compiler says. To get the value inside it, just use the operator deref_mut:
use std::cell::RefCell;
#[derive(Debug)]
struct S {
val: i32
}
fn main() {
let rc: RefCell<Option<S>> = RefCell::new(Some(S{val: 0}));
if let Some(ref mut s2) = *rc.borrow_mut() { // deref_mut
s2.val += 1;
}
println!("{:?}", rc);
}
Related
So I'm trying to implement a linked list in Rust to better understand the language and the following is what I came up with.
use std::rc::Rc;
use std::fmt::Debug;
struct Node<T>
where
T: Debug,
{
value: T,
next: Option<Rc<Box<Node<T>>>>,
}
pub struct LinkedList<T>
where
T: Debug,
{
start: Option<Rc<Box<Node<T>>>>,
end: Option<Rc<Box<Node<T>>>>,
}
I managed to implement the insert method, but I'm having trouble implementing the traverse method.
impl<T> LinkedList<T>
where
T: Debug,
{
pub fn insert(&mut self, value: T) {
let node = Rc::new(Box::new(Node { value, next: None }));
match &mut self.end {
None => {
self.start = Some(Rc::clone(&node));
}
Some(ref mut end_node) => {
if let Some(mutable_node) = Rc::get_mut(end_node) {
mutable_node.next = Some(Rc::clone(&node));
}
}
}
self.end = Some(node);
}
pub fn traverse(&mut self) {
let mut ptr = &mut self.start;
while let Some(ref mut node_rc) = &mut ptr {
let inner_ptr = Rc::get_mut(node_rc).unwrap();
*ptr = inner_ptr.next;
}
}
}
In the traverse method I'm trying to do the basic, initialize a pointer at start and keep moving the pointer forward at each iteration of the loop, but the above traverse implementation gives me the following error
rustc: cannot move out of `inner_ptr.next` which is behind a mutable reference
move occurs because `inner_ptr.next` has type `Option<Rc<Box<Node<T>>>>`, which does not implement the `Copy` trait
which made some sense to me, so I tried modifying my code to
ptr = &mut inner_ptr.next;
but now I get a different error stating
|
56 | while let Some(ref mut node_rc) = &mut ptr {
| -------- borrow of `ptr` occurs here
...
59 | ptr = &mut inner_ptr.next;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| assignment to borrowed `ptr` occurs here
| borrow later used here
I thought I was getting this error because inner_ptr is dropped at the end of each loop iteration, so I made the following change to the traverse method by having inner_ptr's lifetime to equal ptr's lifetime, like so
pub fn traverse(&mut self) {
let mut ptr = &mut self.start;
let mut inner_ptr: &mut Box<Node<T>>;
while let Some(ref mut node_rc) = &mut ptr {
inner_ptr = Rc::get_mut(node_rc).unwrap();
ptr = &mut inner_ptr.next;
}
}
But, the compiler throws the same error in this case as well. Clearly I'm missing something fundamental here about Rust's borrow mechanism, but I can't figure out what
You're taking a mutable reference of ptr when you should't.
pub fn traverse(&mut self) {
let mut ptr = &mut self.start;
while let Some(ref mut node_rc) = ptr { // don't take a mutable reference here
println!("{:?}", node_rc.value);
let inner_ptr = Rc::get_mut(node_rc).unwrap();
ptr = &mut inner_ptr.next;
}
}
You don't want to take a mutable reference there because you don't want to borrow it which would prevent you from changing it later.
Instead you want to move it and replace it every loop.
I got a Box<Rc<RefCell<T>>> from FFI. How can I get the &mut T based on it?
I can not compile it. Compiler tells me:
47 | let mut r: &mut Server = server.borrow_mut();
| ^^^^^^^^^^ the trait BorrowMut<Server> is not implemented for Box<Rc<RefCell<Server>>>
|
= help: the trait BorrowMut<T> is implemented for Box<T, A>
For more information about this error, try rustc --explain E0277.
#[derive(Debug)]
struct Server {
id: i32,
}
impl Server {
pub fn change_id(&mut self) {
self.id = self.id + 1;
}
}
#[no_mangle]
pub extern "C" fn server_change_id(server: *mut Rc<RefCell<Server>>) -> isize {
let server: Box<Rc<RefCell<Server>>> = unsafe { Box::from_raw(server) };
let mut r: &mut Server = server.borrow_mut();
r.change_id();
return 0;
}
Auto-deref will make borrow_mut() directly accessible.
use std::{cell::RefCell, cell::RefMut, ops::DerefMut, rc::Rc};
fn main() {
let a = Box::new(Rc::new(RefCell::new("aaa".to_owned())));
//
println!("{:?}", a);
{
let mut r: RefMut<String> = a.borrow_mut();
r.push_str("bbb"); // via RefMut
let r2: &mut String = r.deref_mut();
r2.push_str("ccc"); // via exclusive-reference
}
println!("{:?}", a);
}
/*
RefCell { value: "aaa" }
RefCell { value: "aaabbbccc" }
*/
In your code, let mut r = server.borrow_mut(); should be enough to invoke r.change_id().
let mut r = server.borrow_mut();
r.change_id();
If you absolutely want a &mut, then use let r2 = r.deref_mut() and invoke r2.change_id().
let mut r = server.borrow_mut();
let r2 = r.deref_mut();
r2.change_id();
T gets wrapped inside the RefCell<T> must implement the Deref or DerefMut trait in order to be borrowed mutably or reference borrowed. In your case, Server must implement a deref method.
use std::ops::DerefMut;
impl DerefMut for Server {
fn deref_mut(&mut self) -> &mut Self {
*self // this assumes your server has more than just one i32 field.
}
}
After this implementation, you should be able to call server.borrow_mut() should work perfectly and return you a mutable server object.
Let's assume the following code:
use std::sync::RwLock;
pub struct NotCloneable(u8);
pub struct Foo {
value: RwLock<Vec<NotCloneable>>,
}
impl Foo {
// does not work
pub fn filter_out_values(&self) {
let mut guard = self.value.write().unwrap();
*guard = guard.into_iter().filter(|nc| nc.0 != 0).collect();
}
}
error[E0507]: cannot move out of borrowed content
--> src/lib.rs:12:18
|
12 | *guard = guard.into_iter().filter(|nc| nc.0 != 0).collect();
| ^^^^^ cannot move out of borrowed content
(playground)
How do I make the function filter_out_values work?
The special circumstance here is, that your T is not Cloneable, therefore you cannot use guard.iter().filter(...).cloned().collect().
I see two options here.
Instead of RwLock<Vec<NotCloneable>> you could use RwLock<Option<Vec<NotCloneable>>> and then use Option::take() to get the value the RwLock was holding and leaving None
You could use std::mem::take(), which is a shortcut for std::mem::replace(v, Default::default()), to get the vec from the guard without triggering the error, because there is no way that you leave the value of the RwLock in an undefined state, where it does not hold any value
use std::sync::RwLock;
pub struct NotCloneable(u8);
pub struct Foo {
value: RwLock<Vec<NotCloneable>>,
}
impl Foo {
pub fn filter_out_values(&self) {
let mut guard = self.value.write().unwrap();
let vec = std::mem::take(&mut *guard);
*guard = vec.into_iter().filter(|nc| nc.0 != 0).collect();
}
}
pub struct Foo1 {
value: RwLock<Option<Vec<NotCloneable>>>,
}
impl Foo1 {
pub fn filter_out_values(&self) {
let mut guard = self.value.write().unwrap();
let vec = guard.take();
*guard = Some(vec.unwrap().into_iter().filter(|nc| nc.0 != 0).collect());
}
}
(playground)
While the other answer is correct, in this case, I'd recommend you to use Vec::retain():
impl Foo {
pub fn filter_out_values(&self) {
let mut guard = self.value.write().unwrap();
guard.retain(|nc| nc.0 != 0);
}
}
It will also be faster.
I want to use the write_fmt method on two different types of object:
use std::fmt::Write;
use std::io::Write;
fn main() {
let mut a = String::new();
let mut b = std::fs::File::create("test").unwrap();
a.write_fmt(format_args!("hello"));
b.write_fmt(format_args!("hello"));
}
I get an error when using Write because they are both named the same:
error[E0252]: a trait named `Write` has already been imported in this module
--> src/main.rs:8:5
|
7 | use std::fmt::Write;
| --------------- previous import of `Write` here
8 | use std::io::Write;
| ^^^^^^^^^^^^^^ `Write` already imported
a.write_fmt(format_args!("hello"));
b.write_fmt(format_args!("hello"));
Or I get an error saying the trait is not available:
error[E0599]: no method named `write_fmt` found for type `std::fs::File` in the current scope
--> src/main.rs:76:4
|
76 | b.write_fmt(format_args!("hello"));
| ^^^^^^^^^
|
= help: items from traits can only be used if the trait is in scope; the following trait is implemented but not in scope, perhaps add a `use` for it:
= help: candidate #1: `use std::io::Write;`
You can call the trait method directly:
fn main() {
let mut a = String::new();
let mut b = std::fs::File::create("test").unwrap();
std::fmt::Write::write_fmt(&mut a, format_args!("hello"));
std::io::Write::write_fmt(&mut b, format_args!("hello"));
}
You can also choose to only import the trait in a smaller scope:
fn main() {
let mut a = String::new();
let mut b = std::fs::File::create("test").unwrap();
{
use std::fmt::Write;
a.write_fmt(format_args!("hello"));
}
{
use std::io::Write;
b.write_fmt(format_args!("hello"));
}
}
Note that if you choose to use a smaller scope, you can also use the write! macro directly:
fn main() {
let mut a = String::new();
let mut b = std::fs::File::create("test").unwrap();
{
use std::fmt::Write;
write!(a, "hello");
}
{
use std::io::Write;
write!(b, "hello");
}
}
In either case, you should handle the Result return value.
See also:
How to call a method when a trait and struct use the same name?
You can specify an alias for use:
use std::fmt::Write as FmtWrite;
use std::io::Write;
fn main() {
let mut a = String::new();
let mut b = std::fs::File::create("test").unwrap();
a.write_fmt(format_args!("hello"));
b.write_fmt(format_args!("hello"));
}
If you just want to call the traits method, you can even just bring them in scope:
use std::fmt::Write as _;
use std::io::Write as _;
fn main() {
let mut a = String::new();
let mut b = std::fs::File::create("test").unwrap();
a.write_fmt(format_args!("hello"));
b.write_fmt(format_args!("hello"));
}
Be careful, this solution works when different types implement different traits with the same name. If the same type implements different traits with the same name, you must use Shepmaster's answer:
mod foo {
pub trait Trait {
fn do_something(&self) {}
}
}
mod bar {
pub trait Trait {
fn do_something(&self) {}
}
}
pub struct Concrete {}
impl foo::Trait for Concrete {}
impl bar::Trait for Concrete {}
fn main() {
let x = Concrete {};
{
use foo::Trait; // use limited to scope
x.do_something(); // call foo::Trait::do_something
}
{
foo::Trait::do_something(&x); // complete path to disambiguate
bar::Trait::do_something(&x); // complete path to disambiguate
}
{
use foo::Trait as FooTrait;
use bar::Trait;
x.do_something(&x); // ERROR: multiple applicable items in scope
}
}
I have a mutable Option type and I'm trying to mutate the thing inside the Some but I can't figure out how to do it.
use std::net::TcpStream;
use std::io::Write;
struct Foo {
stream: Option<TcpStream>,
}
impl Foo {
fn send(&mut self) {
self.stream.map(|x| x.write(b"test")).expect("Couldn't write");
}
}
This produces the error:
error[E0596]: cannot borrow immutable argument `x` as mutable
--> src/main.rs:10:29
|
10 | self.stream.map(|x| x.write(b"test")).expect("Couldn't write");
| - ^ cannot borrow mutably
| |
| consider changing this to `mut x`
Can someone try to implement send as an example to help me understand?
As Vladimir Matveev points out, if let is even nicer, and is more idiomatic than iterating over the Option:
#[derive(Debug)]
struct Foo {
stream: Option<i32>,
}
impl Foo {
fn send(&mut self) {
if let Some(ref mut x) = self.stream {
*x += 1;
}
}
}
fn main() {
let mut f = Foo { stream: Some(0) };
println!("{:?}", f);
f.send();
println!("{:?}", f);
}
As of Rust 1.26, match ergonomics allows you to omit some of the keywords:
impl Foo {
fn send(&mut self) {
if let Some(x) = &mut self.stream {
*x += 1;
}
}
}
Before that, I would usually use Option::as_mut:
impl Foo {
fn send(&mut self) {
if let Some(x) = self.stream.as_mut() {
*x += 1;
}
}
}
Other options
As Vladimir Matveev points out (again!), map is usually used to transform data, not for side effects (which I agree with). You could instead use iter_mut (or the shorthand of &mut collection), as I feel that iteration is usually for side effects. I like this because it means our code can avoid having a conditional:
impl Foo {
fn send(&mut self) {
for x in &mut self.stream {
*x += 1;
}
}
}
You can also leverage the IntoIterator implementation for Option:
impl Foo {
fn send(&mut self) {
for x in self.stream.as_mut() {
*x += 1;
}
}
}
As a follow-up to #idupree's variant, it is also possible to use if-let syntax:
struct Foo {
stream: Option<i32>,
}
impl Foo {
fn send(&mut self) {
if let Some(ref mut x) = self.stream {
*x = 0;
}
}
}
I'd also argue that this is more idiomatic than map(), because map() method is intended for transforming an Option, not executing side effects (and assignment is a side effect).
You can match on the Option directly, like the following (showing i32 rather than TcpStream):
struct Foo {
stream: Option<i32>,
}
impl Foo {
fn send(&mut self) {
match self.stream {
Some(ref mut x) => {
*x = 0;
}
None => {}
}
}
}
(Not sure whether that's the most idiomatic way to do it.)