How to swap non-copyable elements in a vector? [duplicate] - string

This question already has an answer here:
How to swap the elements of an array, slice, or Vec?
(1 answer)
Closed 5 years ago.
I would like to swap String elements of a vector
let mut v_sa: Vec<String> = vec![];
...
let temp_a = v_sa_ib[j];
v_sa_ib[j] = v_sa_ib[j+1];
v_sa_ib[j+1] = temp_a;
It works with integers but not with Strings. I also tried to create a second vector temp_b (same type of temp_a) and to populate it instead of swapping but i got always the same error: the type of this value must be known in this context.
How can I fix it?

You can use the swap() method of Vec to swap two elements directly:
v_sa_ib(j, j+1);
There is also a generic swap function called std::mem::swap but it is difficult to use here because obtaining two mutable references two different elements of the same Vec is quite involved.
The reason why it worked with integers is that integers implement the Copy trait, so Rust can automatically create new copies.

Related

How is Rust persuaded to do an explicit conversion rather than try to save references? [duplicate]

This question already has answers here:
In Rust, what's the difference between "shadowing" and "mutability"?
(1 answer)
Proper way to return a new string in Rust
(2 answers)
Return local String as a slice (&str)
(7 answers)
Why can't I return an &str value generated from a String?
(1 answer)
How do I make format! return a &str from a conditional expression?
(3 answers)
Closed 2 years ago.
How is the following made to work (safely)? There are serious downsides to using 'static.
fn whatever() {
let mut myslice = "goodbye"; //variable that lives, but not necessarily the whole program!
print!("{}", myslice);
{
let mystring = "hello".to_string();
myslice = &*mystring;
}
print!("{}", myslice);
}
The second print should produce 'hello'.
I encounter this problem commonly in lots of forms.
The open bracket could represent multiple things, like calling a function or using an if statement.
E.g.'If there are problems with the value in myslice and things are not working properly. {'
Working out the replacement, (which proved in the above example to be 'hello') is frequently no easy or quick matter, and involves code not to be touched unless it was proved there was a problem. As is normal in Rust, there are many alternatives to &*mystring (&mystring[..], : &str on the left, &*mystring, mystring.as_str(), etc.) but none explicitly manipulate the perfectly available, mutable and live long enough variable as if I had typed let found = "hello".to_string; myslice = &found;' outside the curly brackets. I have tried.clone()` in various places. Why does Rust make such a meal of this simple request? Obviously I am prepared to pay the minuscule processor time to actually do the
request.
I would like a general solution. However, it seems the above problem is explicitly with the type 'String'. e.g. let found = "hello"; let myslice = found; seems to work, even inside the brackets. (found is now &str - it does not seemed ever 'borrowed'.) Is the problem directly or indirectly tied up with not knowing length at compile time? Unfortunately and frequently this is not in my control, I have to use what crates decide to give.

What is the best way to convert a vector of tuples into a hashmap with a value of a vector? [duplicate]

This question already has answers here:
How can I store multiple elements in a Rust HashMap for the same key?
(1 answer)
How do I create a map from a list in a functional way?
(3 answers)
Closed 3 years ago.
I am pretty new to rust, so I have a bit of trouble with the borrow checker. I have a json object which is a vector of the form:
Vec<(String, Option<char>, String)>.
I want to be able to convert this vector into a hash map in order to allow for quick access of each element. Originally, each tuple was unique, and the user would pass a pair of a string and a char, so I had a hashmap of which was of the form HashMap<(String, Option<char>), String>. The conversion function was just an iteration over the original vector passed as a json object like so:
let new_transition_function: Vec<(String, Option<char>, String)> = origin
.transition_function
.iter()
.map(|(x, y, z)| ((x.to_owned(), y.to_owned()), z.to_owned()))
.collect();
However, when the third element is non-unique, the value is jsut replaced in the hashmap, when I need to keep each value. How can I most efficiently and idiomatically transform the old vector of Vec<(String, Option<char>, String)> to a HashMap<(String, Option<char>), Vec<String>)>?

How do I continue using an iterator after calling take? [duplicate]

This question already has answers here:
Using the same iterator multiple times in Rust
(2 answers)
How to use the same iterator twice, once for counting and once for iteration?
(3 answers)
How does one have a for loop borrow the iterator?
(3 answers)
Why does Iterator::take_while take ownership of the iterator?
(2 answers)
Closed 3 years ago.
I want to collect a few items from an iterator, then iterate through the rest, something like this:
let iterator = text.split_whitespace();
let first_ten_words = iterator.take(10).collect();
for word in iterator {
// This should iterate over the remaining words.
}
This doesn't work because take() consumes the iterator.
Obviously I can use split_whitespace() twice and skip(10) but I assume that will do the splitting of the first 10 words twice, and therefore be inefficient.
Is there a better way to do it?
You can use .by_ref() like this:
let iterator = text.split_whitespace();
let first_ten_words = iterator.by_ref().take(10).collect();
for word in iterator {
// This should iterate over the remaining words.
}

How to populate a vector with predefined capacity? [duplicate]

This question already has answers here:
What's the difference between len() and capacity()?
(2 answers)
How to allocate space for a Vec<T> in Rust?
(3 answers)
How do I generate a vector of random numbers in a range?
(2 answers)
Closed 3 years ago.
I am trying to populate a vector after initialising it with with_capacity() as the number of elements is known prior to its creation and it seems more efficient with it.
The following code does NOT populate with random values AT ALL: println!("{}", v.len()); outputs zero.
use rand::Rng;
fn main() {
const NUMBER_OF_RANDOM_NUMBERS: usize = 10;
let mut v = Vec::with_capacity(NUMBER_OF_RANDOM_NUMBERS);
for i in &mut v {
*i += rand::thread_rng().gen_range(1, 2^32);
}
println!("{}", v.len());
}
My thinking is after let mut v = Vec::with_capacity(NUMBER_OF_RANDOM_NUMBERS) a brand new vector gets initialised with 10 zeros and then using rand::thread_rng().gen_range(1, 2^32) to insert, or should I say, add a random number to each zero.
Am I missing something here?
with_capacity does not initialize the values of the vector, it just allocates space for them. From the documentation:
It is important to note that although the returned vector has the
capacity specified, the vector will have a zero length. For an
explanation of the difference between length and capacity, see
Capacity and reallocation.
This means that when your loop code is executed, there are no items in the vector, and therefore it loops a total of zero times. Resulting in no change in the vector.

Creating a slice and appending to it in Rust

In Go, there are make and append functions, from which the first one let's you create a slice of the specified type, length and capacity, whereas the second one let's you append an element to the specified slice. It works more or less like in this toy example:
func main() {
// Creates a slice of type int, which has length 0 (so it is empty), and has capacity 5.
s := make([]int, 0, 5)
// Appends the integer 0 to the slice.
s = append(s, 0)
// Appends the integer 1 to the slice.
s = append(s, 1)
// Appends the integers 2, 3, and 4 to the slice.
s = append(s, 2, 3, 4)
}
Does Rust offer similar features for working with slices?
No.
Go and Rust slices are different:
in Go, a slice is a proxy to another container which allows both observing and mutating the container,
in Rust, a slice is a view in another container which therefore only allows observing the container (though it may allow mutating the individual elements).
As a result, you cannot use a Rust slice to insert, append or remove elements from the underlying container. Instead, you need either:
to use a mutable reference to the container itself,
to design a trait and use a mutable reference to said trait.
Note: Rust std does not provide trait abstractions for its collections unlike Java, but you may still create some yourself if you think it is worth it for a particular problem.

Resources