How to unpack BTreeMap item tuple from an iterator in Rust? - dictionary

Here is example code:
use std::collections::BTreeMap;
fn main() {
let mut map: BTreeMap<u8, Vec<u8>> = BTreeMap::new();
let idx = map.iter_mut().find(|t| {
let (&k, &mut v) = t;
v.is_empty()
});
idx.map(|t| {
let (&k, &mut v) = t;
v.push(5);
});
}
Errors:
<anon>:6:13: 6:25 error: mismatched types:
expected `&(&u8, &mut collections::vec::Vec<u8>)`,
found `(_, _)`
(expected &-ptr,
found tuple) [E0308]
<anon>:6 let (&k, &mut v) = t;
^~~~~~~~~~~~
The type of tuple is &(&u8, &mut collections::vec::Vec<u8>) so I expect it to be unpackable with following:
let (&k, &mut v) = *t;
But
<anon>:10:28: 10:30 error: type `(&u8, &mut collections::vec::Vec<u8>)` cannot be dereferenced
<anon>:10 let (&k, &mut v) = *t;
^~
How to unpack it and use for mutable purposes?

Check out the error message:
expected `&(&u8, &mut collections::vec::Vec<u8>)`,
found `(_, _)`
(expected &-ptr,
found tuple) [E0308]
The compiler expects to match against a reference, but the code does not provide such. Change the binding to let &(&k, &mut v) = t. Then you get a bunch of other errors:
Matching using &mut foo means that foo will have the &mut stripped off, and then the resulting value will be moved to foo. This is because it is a pattern match, just like how let Some(foo) = ... "strips off" the Some.
You can't move the Vec because it's owned by the BTreeMap, so you need to take a reference to it. This is done with the ref keyword, not the & operator.
Normally, you'd also do the pattern matching directly in the closure argument, not in a second variable.
Since map transfers ownership of the item to the closure, you can just give that a mut binding, no need for any references.
As k is unused, it's idiomatic to replace the name with an underscore (_).
let idx = map.iter_mut().find(|&(k, ref v)| {
v.is_empty()
});
idx.map(|(_, mut v)| {
v.push(5);
});
use for mutable purposes
If you mean "how can I mutate the value in the closure to find", the answer is "you can't". Find returns an immutable reference to the iterated item (&Self::Item):
fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
where P: FnMut(&Self::Item) -> bool
Even though your Self::Item might be a mutable reference, an immutable reference to a mutable reference is still immutable.

Related

How to store a pointer to an async method in a container?

I have a struct that defines multiple async methods, and I'd like to store a pointer of each of them in a HashMap, so that I can call any method in one single line, knowing only a key that is given in parameter.
The aim here is to avoid as much as possible to have a huge match clause that would inflate more and more as I add new methods to my struct.
Methods all have the same signature:
async fn handle_xxx(&self, c: Command) -> Result<String, ()>
And I'd really like to call them the following way:
pub async fn execute_command(&mut self, command: Command) -> Result<String, ()> {
let handler = self.command_callbacks.get(&command);
let return_message: String = match handler {
Some(f) => f(self, command).await.unwrap(), // The call is made here.
None => return Err(()),
};
Ok(return_message)
}
However, obviously, in order to store something in a HashMap, you have to specify its type when declaring the HashMap, and that's when the trouble starts.
I tried the most obvious, which is declaring the wrapping function type:
type CommandExecutionNotWorking = fn(&CommandExecutor, Command) -> Future<Output = Result<String, ()>>;
Which does not work since Future is a trait, and not a type.
I tried to declare a generic type and specify it somewhere below:
type CommandExecutionNotWorkingEither<Fut> = fn(&CommandExecutor, Command) -> Fut;
But I encounter the same kind of issue since I need to specify the Future type, and have a HashMap declaration like following:
let mut command_callbacks: HashMap<
Command,
CommandExecutionFn<dyn Future<Output = Result<String, ()>>>,
> = HashMap::new();
impl Future obviously does not work since we're not in a function signature, Future either since it's not a type, and dyn Future creates a legitimate type mismatch.
Thus I tried to use Pin so that I can manipulate dyn Futures, and I ended up with the following signature:
type CommandExecutionStillNotWorking = fn(
&CommandExecutor,
Command,
) -> Pin<Box<dyn Future<Output = Result<String, ()>>>>;
But I need to manipulate functions that return Pin<Box<dyn Future<...>>> and not just Futures. So I tried to define a lambda that take an async function in parameter and returns a function that wraps the return value of my async method in a Pin<Box<...>>:
let wrap = |f| {
|executor, command| Box::pin(f(&executor, command))
};
But the compiler is not happy since it expects me to define the type of f, which is what I tried to avoid here, so I'm back to square one.
Thus my question: Do you know if it's actually possible to write the type of an async function so that pointers on them can be easily manipulated like any variable or any other function pointer?
Or should I go for another solution that may be less elegant, with a bit of duplication code or a huge match structure?
TL;DR: Yes, it is possible, but probably more complicated than you imagined.
First, closures cannot be generic, and thus you'd need a function:
fn wrap<Fut>(f: fn(&CommandExecutor, Command) -> Fut) -> CommandExecution
where
Fut: Future<Output = Result<String, ()>>
{
move |executor, command| Box::pin(f(executor, command))
}
But then you cannot turn the returned closure into a function pointer because it captures f.
Now technically it should be possible since we only want to work with function items (that are non-capturing), and their type (unless converted into a function pointer) is zero-sized. So by the type alone we should be able to construct an instance. But doing that requires unsafe code:
fn wrap<Fut, F>(_f: F) -> CommandExecution
where
Fut: Future<Output = Result<String, ()>>,
F: Fn(&CommandExecutor, Command) -> Fut,
{
assert_eq!(std::mem::size_of::<F>(), 0, "expected a fn item");
move |executor, command| {
// SAFETY: `F` is a ZST (checked above), any (aligned!) pointer, even crafted
// out of the thin air, is valid for it.
let f: &F = unsafe { std::ptr::NonNull::dangling().as_ref() };
Box::pin(f(executor, command))
}
}
(We need _f as a parameter because we cannot specify the function type; let inference find it out itself.)
However, are troubles don't end here. They just start.
Now we get the following error:
error[E0310]: the parameter type `Fut` may not live long enough
--> src/lib.rs:28:9
|
18 | fn wrap<Fut, F>(_f: F) -> CommandExecution
| --- help: consider adding an explicit lifetime bound...: `Fut: 'static`
...
28 | Box::pin(f(executor, command))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `Fut` will meet its required lifetime bounds
Well, it suggests a solution. Let's try...
It compiles! Successfully!!
...until we actually try to make use of it:
let mut _command_callbacks: Vec<CommandExecution> = vec![
wrap(CommandExecutor::handle_xxx),
wrap(CommandExecutor::handle_xxx2),
];
(a HashMap will have the same effect).
error[E0308]: mismatched types
--> src/lib.rs:34:9
|
34 | wrap(CommandExecutor::handle_xxx),
| ^^^^ lifetime mismatch
|
= note: expected associated type `<for<'_> fn(&CommandExecutor, Command) -> impl Future<Output = Result<String, ()>> {CommandExecutor::handle_xxx} as FnOnce<(&CommandExecutor, Command)>>::Output`
found associated type `<for<'_> fn(&CommandExecutor, Command) -> impl Future<Output = Result<String, ()>> {CommandExecutor::handle_xxx} as FnOnce<(&CommandExecutor, Command)>>::Output`
= note: the required lifetime does not necessarily outlive the static lifetime
note: the lifetime requirement is introduced here
--> src/lib.rs:21:41
|
21 | F: Fn(&CommandExecutor, Command) -> Fut,
| ^^^
error[E0308]: mismatched types
--> src/lib.rs:35:9
|
35 | wrap(CommandExecutor::handle_xxx2),
| ^^^^ lifetime mismatch
|
= note: expected associated type `<for<'_> fn(&CommandExecutor, Command) -> impl Future<Output = Result<String, ()>> {CommandExecutor::handle_xxx2} as FnOnce<(&CommandExecutor, Command)>>::Output`
found associated type `<for<'_> fn(&CommandExecutor, Command) -> impl Future<Output = Result<String, ()>> {CommandExecutor::handle_xxx2} as FnOnce<(&CommandExecutor, Command)>>::Output`
= note: the required lifetime does not necessarily outlive the static lifetime
note: the lifetime requirement is introduced here
--> src/lib.rs:21:41
|
21 | F: Fn(&CommandExecutor, Command) -> Fut,
| ^^^
The problem is described in Lifetime of a reference passed to async callback. The solution is to use a trait to workaround the problem:
type CommandExecution = for<'a> fn(
&'a CommandExecutor,
Command,
) -> Pin<Box<dyn Future<Output = Result<String, ()>> + 'a>>;
trait CommandExecutionAsyncFn<CommandExecutor>:
Fn(CommandExecutor, Command) -> <Self as CommandExecutionAsyncFn<CommandExecutor>>::Fut
{
type Fut: Future<Output = Result<String, ()>>;
}
impl<CommandExecutor, F, Fut> CommandExecutionAsyncFn<CommandExecutor> for F
where
F: Fn(CommandExecutor, Command) -> Fut,
Fut: Future<Output = Result<String, ()>>,
{
type Fut = Fut;
}
fn wrap<F>(_f: F) -> CommandExecution
where
F: 'static + for<'a> CommandExecutionAsyncFn<&'a CommandExecutor>,
{
assert_eq!(std::mem::size_of::<F>(), 0, "expected a fn item");
move |executor, command| {
// SAFETY: `F` is a ZST (checked above), any (aligned!) pointer, even crafted
// out of the thin air, is valid for it.
let f: &F = unsafe { std::ptr::NonNull::dangling().as_ref() };
Box::pin(f(executor, command))
}
}
I will not expand on why this thing is needed or how it solves the problem. You can find an explanation in the linked question and the questions linked in it.
And now our code works. Like, truly so.
However, think carefully if you really want all of this stuff: it may be easier to just change the functions to return a boxed future.

How to pass a vector as a parameter in rust

I am trying to write a function that prints a vector. I am having some trouble in understanding how to pass a vector as a parameter. This is what I have so far:
fn vecprinter(v1: &mut Vec<u32>) -> Vec<u32> {
v1
}
fn main(){
let mut v1=vec![1,10,11,12,13];
println!("{:?}", vecprinter(v1));
}
However I am getting this error:
error[E0308]: mismatched types
--> main.rs:3:1
|
1 | fn vecprinter(v1: &mut Vec<u32>) -> Vec<u32> {
| -------- expected `std::vec::Vec<u32>` because of return type
2 |
3 | v1
| ^^
| |
| expected struct `std::vec::Vec`, found mutable reference
| help: try using a conversion method: `v1.to_vec()`
|
= note: expected struct `std::vec::Vec<u32>`
found mutable reference `&mut std::vec::Vec<u32>`
error[E0308]: mismatched types
--> main.rs:10:31
|
10 | println!("{:?}", vecprinter(v1));
| ^^
| |
| expected mutable reference, found struct `std::vec::Vec`
| help: consider mutably borrowing here: `&mut v1`
|
= note: expected mutable reference `&mut std::vec::Vec<u32>`
found struct `std::vec::Vec<{integer}>`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.
compiler exit status 1
What am I doing wrong?
You have two issues here.
Firs your vecprinter method takes a &mut Vec<u32 as a parameter, but you are passing it a Vec<u32> in your call to println!. To resolve this pass a mutable reference t to the vec instead:
println!("{:?}", vecprinter(&mut v1));
The second issue is with the return types of the vecprinter method. You are taking in a &mut Vec<u32> and expecting to return a Vec<u32>; however, when you return the value of v1 you are returning a &mut Vec<u32> rather than the expected Vec<u32>. Depending on your requirements you have two options.
Change the return type of the vecprinter method and pass a mutable reference:
fn vecprinter(v1: &mut Vec<u32>) -> &mut Vec<u32> {
v1
}
fn main(){
let mut v1=vec![1,10,11,12,13];
println!("{:?}", vecprinter(&mut v1));
}
or change the parameter value to take the vector rather than a reference:
fn vecprinter(v1: Vec<u32>) -> Vec<u32> {
v1
}
fn main(){
let mut v1=vec![1,10,11,12,13];
println!("{:?}", vecprinter(v1));
}
You wrote in your question:
I am trying to write a function that prints a vector.
But the function you wrote (no matter if it works or not) is not writing anything: it returns the given vector.
A function which would print something would look like this:
fn print_something(to_print: /*Some type*/) /*No return type*/ {
println!(/*...*/);
}
As you want to print a vector of u32, the prototype could be:
fn print_something(to_print: Vec<u32>) { /*...*/ }
But if you do that, the argument will be moved into the function and will become unusable outside of it. In order to improve this, you can pass the argument as a reference:
fn print_something(to_print: &Vec<u32>) { /*...*/ }
To handle more general cases (&Vec<u32> + &[u32]), you can still improve it like this:
fn print_something(to_print: &[u32]) { /*...*/ }
Now when you call this function, you have to add an ampersamp & to the given argument (unless it's already a reference):
print_something(&my_vector);
Finally, by gluing everything together, you have this:
fn print_vec(v: &[u32]) {
println!("{:?}", v);
}
fn main() {
let v = vec![1, 10, 11, 12, 13];
print_vec(&v);
// Because we changed "&Vec<u32>" to "&[u32]", the following is also
// possible:
let arr = &[1, 10, 11, 12, 13];
print_vec(arr);
}

How to update all the values in a BTreeSet?

I have collection which is a field in a struct in some module. I want to update all the values in the collection from another module.
I wrote some code to mimic what I want to achieve. It's shortened a bit, but I think it has all needed parts. There is no struct holding the collection in this code, but imagine this is a getter which returns the collection. I added in comments how I think it should look.
pub mod pos {
use std::cmp::{Ordering, PartialEq};
#[derive(PartialOrd, PartialEq, Eq, Hash, Debug, Copy, Clone)]
pub struct Pos {
pub x: i32,
pub y: i32,
}
#[allow(dead_code)]
impl Pos {
pub fn of(x: i32, y: i32) -> Self {
Self { x, y }
}
pub fn offset(&mut self, pos: &Self) -> Self {
self.x += pos.x;
self.y += pos.y;
*self
}
}
impl Ord for Pos {
fn cmp(&self, other: &Self) -> Ordering {
if self.x < other.x {
Ordering::Less
} else if self.eq(other) {
Ordering::Equal
} else {
Ordering::Greater
}
}
}
}
mod test {
use crate::pos::Pos;
use std::collections::BTreeSet;
#[test]
fn test_iterators() {
let mut data_in_some_strct: BTreeSet<Pos> = BTreeSet::new();
data_in_some_strct.insert(Pos::of(1, 1));
data_in_some_strct.insert(Pos::of(2, 2));
data_in_some_strct.insert(Pos::of(3, 3));
data_in_some_strct.insert(Pos::of(4, 4));
// mimic getter call ( get_data(&mut self) -> &BTreeSet<Pos> {...}
// let set = data_in_some_strct; // works, but not a reference
let set = &data_in_some_strct; // doesn't work, How to adjust code to make it work??
data_in_some_strct = set
.into_iter()
.map(|mut p| p.offset(&Pos::of(1, 0)))
.inspect(|p| println!("{:?}", *p))
.collect();
assert_eq!(data_in_some_strct.contains(&Pos::of(2, 1)), true);
assert_eq!(data_in_some_strct.contains(&Pos::of(3, 2)), true);
assert_eq!(data_in_some_strct.contains(&Pos::of(4, 3)), true);
assert_eq!(data_in_some_strct.contains(&Pos::of(5, 4)), true);
}
}
Playground
error[E0596]: cannot borrow `*p` as mutable, as it is behind a `&` reference
--> src/lib.rs:56:26
|
56 | .map(|mut p| p.offset(&Pos::of(1, 0)))
| - ^ `p` is a `&` reference, so the data it refers to cannot be borrowed as mutable
| |
| help: consider changing this to be a mutable reference: `&mut pos::Pos`
I managed to make it work without borrowing, but I would like to make it work with borrowing. I guess there is more then one way to achieve it. Comments to help my Rust brain dendrites connect are welcome.
You can't mutate items that are part of a HashSet or BTreeSet because the value of the items determines how they are stored and accessed. If you mutate them then, as Stargateur mentioned, you would break the mechanics of the collection. In the case of a HashSet, you would change the hash of the item, which determines the location where the data is stored. In the case of a BTreeSet, the algorithm is based on how the items are sorted.
You are able to do it by taking ownership because you consume the original set and produce a new, well-formed one. You can't take ownership of a borrowed value because that would leave behind a dangling pointer, which Rust will not let you do.
One possible solution is to temporarily replace the original set with an empty one. Then you can take ownership of its contents, as in your working code, and finally write the newly updated set over the original:
let set = std::mem::replace(&mut data_in_some_strct, BTreeSet::new());
data_in_some_strct = set.into_iter()
.map(|mut p| p.offset(&Pos::of(1,0)))
.inspect(|p| println!("{:?}", *p))
.collect();
BTreeSet doesn't implement impl<'a, T> IntoIterator for &'a mut BTreeSet<T> (that would break the tree).
You can only do this with types that implement IntoIterator with mut like impl<'a, T> IntoIterator for &'a mut Vec<T>, example.
For sets that are not a field of a struct
Even std::mem::replace is not required.
data_in_some_strct = data_in_some_strct
.into_iter()
.map(|mut p| p.offset(&Pos::of(1, 0)))
.inspect(|p| println!("{:?}", *p))
.collect();
Explanation
We essentially build an iterator for moving out the BTreeSet’s contents.
Then we call .map() over the elements and call the required methods.
It should be noted that it works here because .offset(...) returns Self. If the method does not return Self, you can simply write:
// ...
.map(|mut p| {
p.offset(&Pos::of(1, 0));
p
})
// ...
At last, we use .collect() to construct a BTreeSet with all newly "updated" values.
For sets that are a field of a struct
Let's assume that the field's name is data_in_some_strct of some given struct Foobar.
struct Foobar {
data_in_some_strct: BTreeSet<Pos>,
}
Let's say hypothetically we also have method called Foobar::update() that updates the values in the set.
impl Foobar {
fn update(&mut self) {
// ...
}
}
To update the set from within, we'd have to use std::mem::take().
fn update(&mut self) {
self.data_in_some_strct = std::mem::take(&mut self.data_in_some_strct)
.into_iter()
.map(|mut p| p.offset(&Pos::of(1, 0)))
.inspect(|p| println!("{:?}", *p))
.collect();
}
Explanation
The key takeaway here is std::mem::take()'s usage. It's doc says:
[It] Replaces dest with the default value of T, returning the previous dest value.
This essentially means that the destination value (here data_in_some_strct) is replaced with a default value (which happens to be an empty set for BTreeSet), and the original value is returned.
We then perform the same operations on the value returned by take() as in the previous explanation above.
As stated above, collect() builds a new BTreeSet for us by inferring its type from self.data_in_some_strct. We then move the newly created BTreeSet to self.data_in_some_strct.
Note: You can replace *p with p.
This is especially valuable and noteworthy for people who will use (or are
already using) Rc<RefCell<T>> or its thread safe variant.
Instead of using map() to mutate the values in-place, thus putting the code at risk of logic error, one should follow the steps above.

Print Vec using a placeholder [duplicate]

I tried the following code:
fn main() {
let v2 = vec![1; 10];
println!("{}", v2);
}
But the compiler complains:
error[E0277]: `std::vec::Vec<{integer}>` doesn't implement `std::fmt::Display`
--> src/main.rs:3:20
|
3 | println!("{}", v2);
| ^^ `std::vec::Vec<{integer}>` cannot be formatted with the default formatter
|
= help: the trait `std::fmt::Display` is not implemented for `std::vec::Vec<{integer}>`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
= note: required by `std::fmt::Display::fmt`
Does anyone implement this trait for Vec<T>?
let v2 = vec![1; 10];
println!("{:?}", v2);
{} is for strings and other values which can be displayed directly to the user. There's no single way to show a vector to a user.
The {:?} formatter can be used to debug it, and it will look like:
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
Display is the trait that provides the method behind {}, and Debug is for {:?}
Does anyone implement this trait for Vec<T> ?
No.
And surprisingly, this is a demonstrably correct answer; which is rare since proving the absence of things is usually hard or impossible. So how can we be so certain?
Rust has very strict coherence rules, the impl Trait for Struct can only be done:
either in the same crate as Trait
or in the same crate as Struct
and nowhere else; let's try it:
impl<T> std::fmt::Display for Vec<T> {
fn fmt(&self, _: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
Ok(())
}
}
yields:
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
--> src/main.rs:1:1
|
1 | impl<T> std::fmt::Display for Vec<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
|
= note: only traits defined in the current crate can be implemented for a type parameter
Furthermore, to use a trait, it needs to be in scope (and therefore, you need to be linked to its crate), which means that:
you are linked both with the crate of Display and the crate of Vec
neither implement Display for Vec
and therefore leads us to conclude that no one implements Display for Vec.
As a work around, as indicated by Manishearth, you can use the Debug trait, which is invokable via "{:?}" as a format specifier.
If you know the type of the elements that the vector contains, you could make a struct that takes vector as an argument and implement Display for that struct.
use std::fmt::{Display, Formatter, Error};
struct NumVec(Vec<u32>);
impl Display for NumVec {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
let mut comma_separated = String::new();
for num in &self.0[0..self.0.len() - 1] {
comma_separated.push_str(&num.to_string());
comma_separated.push_str(", ");
}
comma_separated.push_str(&self.0[self.0.len() - 1].to_string());
write!(f, "{}", comma_separated)
}
}
fn main() {
let numbers = NumVec(vec![1; 10]);
println!("{}", numbers);
}
Here is a one-liner which should also work for you:
println!("[{}]", v2.iter().fold(String::new(), |acc, &num| acc + &num.to_string() + ", "));
Here is
a runnable example.
In my own case, I was receiving a Vec<&str> from a function call. I did not want to change the function signature to a custom type (for which I could implement the Display trait).
For my one-of case, I was able to turn the display of my Vec into a one-liner which I used with println!() directly as follows:
println!("{}", myStrVec.iter().fold(String::new(), |acc, &arg| acc + arg));
(The lambda can be adapted for use with different data types, or for more concise Display trait implementations.)
Starting with Rust 1.58, there is a slightly more concise way to print a vector (or any other variable). This lets you put the variable you want to print inside the curly braces, instead of needing to put it at the end. For the debug formatting needed to print a vector, you add :? in the braces, like this:
fn main() {
let v2 = vec![1; 10];
println!("{v2:?}");
}
Sometimes you don't want to use something like the accepted answer
let v2 = vec![1; 10];
println!("{:?}", v2);
because you want each element to be displayed using its Display trait, not its Debug trait; however, as noted, you can't implement Display on Vec because of Rust's coherence rules. Instead of implementing a wrapper struct with the Display trait, you can implement a more general solution with a function like this:
use std::fmt;
pub fn iterable_to_str<I, D>(iterable: I) -> String
where
I: IntoIterator<Item = D>,
D: fmt::Display,
{
let mut iterator = iterable.into_iter();
let head = match iterator.next() {
None => return String::from("[]"),
Some(x) => format!("[{}", x),
};
let body = iterator.fold(head, |a, v| format!("{}, {}", a, v));
format!("{}]", body)
}
which doesn't require wrapping your vector in a struct. As long as it implements IntoIterator and the element type implements Display, you can then call:
println!("{}", iterable_to_str(it));
Is there any reason not to write the vector's content item by item w/o former collecting? *)
use std::fmt::{Display, Formatter, Error};
struct NumVec(Vec<u32>);
impl Display for NumVec {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
let v = &self.0;
if v.len() == 0 {
return Ok(());
}
for num in &v[0..v.len() - 1] {
if let Err(e) = write!(f, "{}, ", &num.to_string()) {
return Err(e);
}
}
write!(f, "{}", &v[v.len() - 1])
}
}
fn main() {
let numbers = NumVec(vec![1; 10]);
println!("{}", numbers);
}
*) No there isn't.
Because we want to display something, the Display trait is implemented for sure. So this is correct Rust because: the Doc says about the ToString trait:
"This trait is automatically implemented for any type which implements the Display trait. As such, ToString shouldn’t be implemented directly: Display should be implemented instead, and you get the ToString implementation for free."
In particular on microcontrollers where space is limited I definitely would go with this solution and write immediately.

Generic map as function argument

I wrote a method:
fn foo(input: HashMap<String, Vec<String>>) {...}
I then realized that for the purpose of writing tests, I'd like to have control of the iteration order (maybe a BTreeMap or LinkedHashMap). This led to two questions:
Is there some trait or combination of traits I could use that would essentially express "a map of string to string-vector"? I didn't see anything promising in the docs for HashMap.
It turns out that in this method, I just want to iterate over the map entries, and then the items in each string vector, but couldn't figure out the right syntax for specifying this. What's the correct way to write this?
fn foo(input: IntoIterator<(String, IntoIterator<String>)>) {...}
There's no such trait to describe an abstract HashMap. I believe there's no plan to make one. The best answer so far is your #2 suggestion: for a read-only HashMap you probably just want something to iterate on.
To answer at the syntax level, you tried to write:
fn foo(input: IntoIterator<(String, IntoIterator<String>)>)
But this is not valid because IntoIterator takes no template argument:
pub trait IntoIterator where Self::IntoIter::Item == Self::Item {
type Item;
type IntoIter: Iterator;
fn into_iter(self) -> Self::IntoIter;
}
It takes two associated types, however, so what you really wanted to express is probably the following (internally I changed the nested IntoIterator to a concrete type like Vec for simplicity):
fn foo<I>(input: I)
where I: IntoIterator<
Item=(String, Vec<String>),
IntoIter=IntoIter<String, Vec<String>>>
However the choice if IntoIterator is not always suitable because it implies a transfer of ownership. If you just wanted to borrow the HashMap for read-only purposes, you'd be probably better with the standard iterator trait of a HashMap, Iterator<Item=(&'a String, &'a Vec<String>)>.
fn foo_iter<'a, I>(input: I)
where I: Iterator<Item=(&'a String, &'a Vec<String>)>
Which you can use several times by asking for a new iterator, unlike the first version.
let mut h = HashMap::new();
h.insert("The Beatles".to_string(),
vec!["Come Together".to_string(),
"Twist And Shout".to_string()]);
h.insert("The Rolling Stones".to_string(),
vec!["Paint It Black".to_string(),
"Satisfaction".to_string()]);
foo_iter(h.iter());
foo_iter(h.iter());
foo(h);
//foo(h); <-- error: use of moved value: `h`
Full gist
EDIT
As asked in comments, here is the version of foo for nested IntoIterators instead of the simpler Vec:
fn foo<I, IVecString>(input: I)
where
I: IntoIterator<
Item=(String, IVecString),
IntoIter=std::collections::hash_map::IntoIter<String, IVecString>>,
IVecString: IntoIterator<
Item=String,
IntoIter=std::vec::IntoIter<String>>
There are not traits that define a common interface for containers. The only trait that maybe is suited for your is the Index trait.
See below for a working example of the correct syntax for IntoIterator and the Index traits. You need to use references if you don't want consume the input, so be careful with lifetime parameters.
use std::ops::Index;
use std::iter::IntoIterator;
use std::collections::HashMap;
// this consume the input
fn foo<I: IntoIterator<Item = (String, String)>>(input: I) {
let mut c = 0;
for _ in input {
c += 1;
}
println!("{}", c);
}
// maybe you want this
fn foo_ref<'a, I: IntoIterator<Item = (&'a String, &'a String)>>(input: I) {
let mut c = 0;
for _ in input {
c += 1;
}
println!("{}", c);
}
fn get<'a, I: Index<&'a String, Output = String>>(table: &I, k: &'a String) {
println!("{}", table[k]);
}
fn main() {
let mut h = HashMap::<String, String>::new();
h.insert("one".to_owned(), "1".to_owned());
h.insert("two".to_owned(), "2".to_owned());
h.insert("three".to_owned(), "3".to_owned());
foo_ref(&h);
get(&h, &"two".to_owned());
}
Edit
I changed the value type to everything implements the IntoIterator trait :
use std::ops::Index;
use std::iter::IntoIterator;
use std::collections::HashMap;
use std::collections::LinkedList;
fn foo_ref<'a, B, I, >(input: I)
where B : IntoIterator<Item = String>, I: IntoIterator<Item = (&'a String, &'a B)> {
//
}
fn get<'a, B, I>(table: &I, k: &'a String)
where B : IntoIterator<Item = String>, I: Index<&'a String, Output = B>
{
// do something with table[k];
}
fn main() {
let mut h1 = HashMap::<String, Vec<String>>::new();
let mut h2 = HashMap::<String, LinkedList<String>>::new();
foo_ref(&h1);
get(&h1, &"two".to_owned());
foo_ref(&h2);
get(&h2, &"two".to_owned());
}

Resources