How to join arrays like JavaScript's destructuring? - functional-programming

I want to make a function that receives a Vec and a position to change a number.
In JavaScript, this is really simple:
function replaceNumber(line, position, number) {
return [
...line.slice(0, position),
number,
...line.slice(position+1, line.length)
]
}
How can I make a similar function in Rust?
I tried this:
fn replace_number(line: Vec<i32>, point: i32, number: i32) -> Vec<i32> {
return [
&line[0..point as usize],
&[number],
&line[point as usize+1, point.len()]
].concat();
}
The result is an array of arrays. How can I make a destructuring like the JavaScript example?

I want to make a function that receives a Vec and a position to change a number.
Rust has indexing syntax, just like JavaScript, so there's really no need for the destructuring.
fn replace_number(mut line: Vec<i32>, point: usize, number: i32) -> Vec<i32> {
line[point] = number;
line
}
or, more idiomatically:
fn replace_number(line: &mut Vec<i32>, point: usize, number: i32) {
line[point] = number
}
Even more idiomatically would be to not have this function, probably, and just write it inline...
I want to know about immutably adding
With your original code, there's zero concern about anything "bad" happening because of mutability:
fn replace_number(line: Vec<i32>, point: i32, number: i32) -> Vec<i32>
This function takes ownership of the Vec, so the concept of immutability is rather moot here — the caller no longer has the Vec to care if it's mutated or not!
If you wanted to share data, you'd use a reference (a slice, specifically) like &[i32]. This is inherently immutable — you can't change it if you wanted to. You'd have to clone all the children and make the vector mutable:
fn replace_number(line: &[i32], point: usize, number: i32) -> Vec<i32> {
let mut line = line.to_owned();
line[point] = number;
line
}
If you really wanted something like the JS syntax, you can use concat:
fn replace_number(line: &[i32], point: usize, number: i32) -> Vec<i32> {
[&line[..point], &[number], &line[point + 1..]].concat()
}
See also:
Why is it discouraged to accept a reference to a String (&String), Vec (&Vec) or Box (&Box) as a function argument?

Related

How do I declare a regular (non-closure) function that adheres to a function type?

I have a collection of different sort functions with a common signature so they can be passed interchangeably to other functions. I want to be able to declare inline that each should match the same signature, so I'll be warned contextually if one of them breaks with it.
Rust has a syntax for declaring function types:
type Foo = Fn(i32) -> i32;
fn bar(func: &Foo) {
func(12);
}
What I can't figure out is how to declare a regular (non-closure) function that adheres to a function type:
// this works and can be passed as a Foo, but
// duplicates code and isn't checked against Foo
fn blah(x: i32) -> i32 {
return x * 2;
}
// this isn't valid syntax
fn blah(x): Foo {
return x * 2;
}
This is common practice in some other languages that have function types. Is there a syntax I don't know about, is this an upcoming feature, or is there some technical reason preventing it from being added to Rust?
Note; something like this would also serve my purpose, even though it'd be more clunky:
fn blah(x: i32) -> i32 {
return x * 2;
}: Foo
Rust has a syntax for declaring function types:
type Foo = Fn(i32) -> i32;
This is not such a syntax (as you might infer by the fact that it doesn't do what you want). This creates a type alias of the type dyn Fn(i32) -> i32.
You can achieve some of what you want by using a function pointer and creating an unused variable set to the function:
type MyType = fn(i32) -> i32;
fn blah(x: i32) -> i32 {
x * 2
}
const _IGNORE: MyType = blah;
However, I agree with the comments that you are going about this in a non-idiomatic Rust manner. You want to create an interface that things adhere to, and in Rust that's a trait:
trait Sort {
fn foo(_: i32) -> i32;
}
struct A;
impl Sort for A {
fn foo(x: i32) -> i32 {
x * 2
}
}
This prevents accidentally "crossing the streams" by providing a fn(String) when you meant an fn(String); the former being "print this string" and the latter being "delete the file named". Function signatures are, at best, a weak interface.
See also:
What does "dyn" mean in a type?
How to enforce that a type implements a trait at compile time?

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.

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

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.

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());
}

Incomprehensible behaivior of () -> &str function

I'm new in rust and don't understand one moment:
Pointer's Guide says: "You don't really should return pointers". I'm okay with that, but in my HelloWorld-like program I tried to return &str. I don't need boxed String, just &str to immediately print it. And I succeeded in this chalenge, but only partially.
So, question itself:
Why I can do
fn foo(p: &[uint]) -> &str { "STRING" }
, but can't do
fn foo(p: Vec<uint>) -> &str { "STRING" } //error: missing lifetime specifier [E0106]
, but still can do
fn foo(p: Vec<uint>) -> &'static str { "STRING" }
What changes fact of switching from slice to Vec?
P.S. Sorry for my dummy english and dummy question. I think, I just don't get a point of rust's borrow-checher
This is how lifetime specifiers are automatically added:
This:
fn foo(p: &[uint]) -> &str { "STRING" }
In the past you had to write it explicilty:
fn foo<'a>(p: &'a [uint]) -> &'a str { "STRING" }
These two are equivalent (but not really accurate since input p and returned str are not related). It works because 'static > 'a so is always valid for any lifetime.
The second example wont work because there is no input reference so no automatic lifetime
parameters are added and the whole thing makes no sense (every reference needs a lifetime, explicit or implicit):
fn foo(p: Vec<uint>) -> &str { "STRING" }
As you already did you fix it by adding the lifetime to it:
fn foo(p: Vec<uint>) -> &'static str { "STRING" }

Resources