For a non copy type, like HashMap<String, String> for example, how can I convert from Option<&T> to &Option (without cloning) ? (seems like I am looking for "the opposite" of .as_ref(), but as_deref() is not it)
You can't convert from Option<&T> to &Option<T> because that would mean moving the value out from behind the shared reference &T.
Rust's rules prevent that with good reason: there could be multiple shared references to an object, so moving the object would leave the other references dangling.
You can, however, move out of a mutable reference using std::mem::take, so you can convert an Option<&mut T> to &Option<T> like this:
let h : HashMap<String,String> = HashMap::new();
let mut o1 = Some(h); // Option<T>
let o2 = o1.as_mut(); // Option<&mut T>
let o3 = &o2.map(std::mem::take); // &Option<T>
Note that take replaces the argument with the default value of T, so you can only use it if T implemented Default. Other options are to use replace or swap.
Related
I have a function that takes in a Vec<String> value. I want to use this function on values contained inside my_ref, so I need to extract a Vec<String> out of a Rc<RefCell<Vec<String>>>.
I thought I could do this by dereferencing a borrow of my my_ref, just like I would for a Rc<RefCell<f32>>> or Rc<RefCell<i32>>> value:
use std::cell::RefCell;
use std::rc::Rc;
fn main() {
let my_ref = Rc::from(RefCell::from(vec![
"Hello 1".to_string(),
"Hello 2".to_string(),
]));
let my_strings: Vec<String> = *my_ref.borrow();
let count = count_strings(my_strings);
}
fn count_strings(strings: Vec<String>) -> usize {
strings.len()
}
But doing so results in a dereferencing error:
error[E0507]: cannot move out of dereference of `Ref<'_, Vec<String>>`
cannot move out of dereference of `Ref<'_, Vec<String>>`
move occurs because value has type `Vec<String>`, which does not implement the `Copy` trait
So then, how do I properly extract a Vec<String> from a Rc<RefCell<Vec<String>>>?
RefCell::borrow returns a reference, not an owned value, that's why you having such an error. I can name two different solution for that problem.
Promoting Rc to exclusively-owned type
Rc::try_unwrap is able to check, whether there's other references to the data. If it's the only one, it can be safely converted to the inner type. Then, an owned RefCell can be converted into its inner via into_inner function.
let my_ref = Rc::from(RefCell::new(vec![..]));
let inner: Vec<_> = Rc::try_unwrap(my_ref).expect("I hereby claim that my_ref is exclusively owned").into_inner();
Replacing inner value
If for some reason you want to grab inner value that is already referenced, you may consider replacing it. Note, that you need to create a appropriate value for the type (i.e. with trait Default). Here's the example:
let my_ref = Rc::from(RefCell::new(vec![..]));
let inner: Vec<_> = my_ref.borrow_mut().take();
// or
let inner: Vec<_> = my_ref.borrow_mut().replace(vec![]);
I have a HashMap with Option<String> keys; is it possible to do lookups with a key of type Option<&str>? I know I can use a &str to lookup in a HashMap<String, V> because str implements Borrow<String>.
Do I have to convert to an owned string just to do a lookup?
It's slightly less efficient, but you could use Cow here. It avoids the problem with the Borrow trait by instead having a single type that can represent either a reference or an owned value, like so:
use std::borrow::Cow;
use std::collections::HashMap;
fn main() {
let mut map = HashMap::<Option<Cow<'static, str>>, i32>::new();
map.insert(None, 5);
map.insert(Some(Cow::Borrowed("hello")), 10);
map.insert(Some(Cow::Borrowed("world")), 15);
// works with None and constant string slices...
assert_eq!(map.get(&None), Some(&5));
assert_eq!(map.get(&Some(Cow::Borrowed("hello"))), Some(&10));
// ...and also works with heap-allocated strings, without copies
let stack = String::from("world");
assert_eq!(map.get(&Some(Cow::Borrowed(&stack))), Some(&15));
}
Is there a more efficient way of getting an owned value from a HashMap than this line?
let output_items = output_tables.get(TABLE_NAME_TLIST).unwrap().to_owned();
This screenshot expands the types:
relates to Rust - Change a reference to own value without clone
If you want to take ownership of the value, HashMap::remove() will return an Option<T> rather than the Option<&T> returned by HashMap::get(). See this playground:
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert(1, "a");
assert_eq!(map.remove(&1), Some("a"));
assert_eq!(map.remove(&1), None);
}
If you want the value to remain in the HashMap but also own the value elsewhere, you can wrap it in an Rc<T> to share ownership. If the object needs to be mutable, you can wrap it in an Rc<RefCell<T>>.
First of all, I'm not asking what's the difference between &mut and ref mut per se.
I'm asking because I thought:
let ref mut a = MyStruct
is the same as
let a = &mut MyStruct
Consider returning a trait object from a function. You can return a Box<Trait> or a &Trait. If you want to have mutable access to its methods, is it possible to return &mut Trait?
Given this example:
trait Hello {
fn hello(&mut self);
}
struct English;
struct Spanish;
impl Hello for English {
fn hello(&mut self) {
println!("Hello!");
}
}
impl Hello for Spanish {
fn hello(&mut self) {
println!("Hola!");
}
}
The method receives a mutable reference for demonstration purposes.
This won't compile:
fn make_hello<'a>() -> &'a mut Hello {
&mut English
}
nor this:
fn make_hello<'a>() -> &'a mut Hello {
let b = &mut English;
b
}
But this will compile and work:
fn make_hello<'a>() -> &'a mut Hello {
let ref mut b = English;
b
}
My theory
This example will work out of the box with immutable references (not necessary to assign it to a variable, just return &English) but not with mutable references. I think this is due to the rule that there can be only one mutable reference or as many immutable as you want.
In the case of immutable references, you are creating an object and borrowing it as a return expression; its reference won't die because it's being borrowed.
In the case of mutable references, if you try to create an object and borrow it mutably as a return expression you have two mutable references (the created object and its mutable reference). Since you cannot have two mutable references to the same object it won't perform the second, hence the variable won't live long enough. I think that when you write let mut ref b = English and return b you are moving the mutable reference because it was captured by a pattern.
All of the above is a poor attempt to explain to myself why it works, but I don't have the fundamentals to prove it.
Why does this happen?
I've also cross-posted this question to Reddit.
This is a bug. My original analysis below completely ignored the fact that it was returning a mutable reference. The bits about promotion only make sense in the context of immutable values.
This is allowable due to a nuance of the rules governing temporaries (emphasis mine):
When using an rvalue in most lvalue contexts, a temporary unnamed lvalue is created and used instead, if not promoted to 'static.
The reference continues:
Promotion of an rvalue expression to a 'static slot occurs when the expression could be written in a constant, borrowed, and dereferencing that borrow where the expression was the originally written, without changing the runtime behavior. That is, the promoted expression can be evaluated at compile-time and the resulting value does not contain interior mutability or destructors (these properties are determined based on the value where possible, e.g. &None always has the type &'static Option<_>, as it contains nothing disallowed).
Your third case can be rewritten as this to "prove" that the 'static promotion is occurring:
fn make_hello_3<'a>() -> &'a mut Hello {
let ref mut b = English;
let c: &'static mut Hello = b;
c
}
As for why ref mut allows this and &mut doesn't, my best guess is that the 'static promotion is on a best-effort basis and &mut just isn't caught by whatever checks are present. You could probably look for or file an issue describing the situation.
I'm trying to implement the following code, which removes the prefix from a slice of Cow<str>'s.
fn remove_prefix(v: &mut [Cow<str>], prefix: &str) {
for t in v.iter_mut() {
match *t {
Borrowed(&s) => s = s.trim_left_matches(prefix),
Owned(s) => s = s.trim_left_matches(prefix).to_string(),
}
}
}
I have two questions:
I can't get this to compile - I've tried loads of combinations of &'s and *'s but to no avail.
Is there a better way to apply functions to a Cow<str> without having to match it to Borrowed and Owned every time. I mean it seems like I should just be able to do something like *t = t.trim_left_matches(prefix) and if t is a Borrowed(str) it leaves it as a str (since trim_left_matches allows that), and if it is an Owned(String) it leaves it as a String. Similarly for replace() it would realise it has to convert both to a String (since you can't use replace() on a str). Is something like that possible?
Question #1 strongly implies how you think pattern matching and/or pointers work in Rust doesn't quite line up with how they actually work. The following code compiles:
fn remove_prefix(v: &mut [Cow<str>], prefix: &str) {
use std::borrow::Cow::*;
for t in v.iter_mut() {
match *t {
Borrowed(ref mut s) => *s = s.trim_left_matches(prefix),
Owned(ref mut s) => *s = s.trim_left_matches(prefix).to_string(),
}
}
}
If your case, Borrowed(&s) is matched against Borrowed(&str), meaning that s is of type str. This is impossible: you absolutely cannot have a variable of a dynamically sized type. It's also counter-productive. Given that you want to modify s, binding to it by value won't help at all.
What you want is to modify the thing contained in the Borrowed variant. This means you want a mutable pointer to that storage location. Hence, Borrowed(ref mut s): this is not destructuring the value inside the Borrowed at all. Rather, it binds directly to the &str, meaning that s is of type &mut &str; a mutable pointer to a (pointer to a str). In other words: a mutable pointer to a string slice.
At that point, mutating the contents of the Borrowed is done by re-assigning the value through the mutable pointer: *s = ....
Finally, the exact same reasoning applies to the Owned case: you were trying to bind by-value, then mutate it, which cannot possibly do what you want. Instead, bind by mutable pointer to the storage location, then re-assign it.
As for question #2... not really. That would imply some kind of overloading, which Rust doesn't do (by deliberate choice). If you are doing this a lot, you could write an extension trait that adds methods of interest to Cow.
You can definitely do it.
fn remove_prefix(v: &mut [Cow<str>], prefix: &str) {
for t in v.iter_mut() {
match *t {
Cow::Borrowed(ref mut s) => *s = s.trim_left_matches(prefix),
Cow::Owned(ref mut s) => *s = s.trim_left_matches(prefix).to_string(),
}
}
}
ref mut s means “take a mutable reference to the value and call it s” in a pattern. Thus you have s of type &mut &str or &mut String. You must then use *s = in order to change what that mutable reference is pointing to (thus, change the string inside the Cow).