How do I parse a vector into a function? - rust

The idea is to send a set of characters of a vector and let the function display the current correct guesses.
Here is my main:
fn main() {
let mut guessedLetters = vec![];
displayWord(guessedLetters);
}
And here is the function:
fn displayWord(correctGuess: Vec<char>) {
let mut currentWord = String::new();
for x in 0..5 {
currentWord.push(correctGuess[x]);
}
println!("Current guesses: {}", currentWord);
}
I don't know what I'm supposed to write inside the parameters of displayWord.

There's a couple of things wrong with your code.
The first error is pretty straight forward:
--> src/main.rs:38:25
|
38 | displayWord(guessed_Letters);
| ^^^^^^^^^^^^^^^ expected char, found enum `std::option::Option`
|
= note: expected type `std::vec::Vec<char>`
found type `std::vec::Vec<std::option::Option<char>>`
The function you wrote is expecting a vector a characters ... but you're passing it a vector of Option<char>. This is happening here:
guessed_Letters.push(line.chars().nth(0));
According to the documentation, the nth method returns an Option. The quick fix here is to unwrap the Option to get the underlying value:
guessed_Letters.push(line.chars().nth(0).unwrap());
Your next error is:
error[E0382]: use of moved value: `guessed_Letters`
--> src/main.rs:38:25
|
38 | displayWord(guessed_Letters);
| ^^^^^^^^^^^^^^^ value moved here in previous iteration of loop
|
= note: move occurs because `guessed_Letters` has type `std::vec::Vec<char>`, which does not implement the `Copy` trait
This is transferring ownership of the vector on the first iteration of the loop and the compiler is telling you that subsequent iterations would be in violation of Rust's ownership rules.
The solution here is to pass the vector by reference instead:
displayWord(&guessed_Letters);
..and your method should also accept a reference:
fn displayWord(correctGuess: &Vec<char>) {
let mut currentWord = String::new();
for x in 0..5 {
currentWord.push(correctGuess[x]);
}
println!("Current guesses: {}", currentWord);
}
This can be shortened to use a slice and still work:
fn displayWord(correctGuess: &[char]) {

Related

Rust String::to_bytes | What does the Rust compiler mean here, exactly?

I am newbie in the Rust world.
As an exercise, this is the problem I am trying to solve:
fn main() {
let s = give_ownership();
println!("{}", s);
}
// Only modify the code below!
fn give_ownership() -> String {
let s = String::from("hello, world");
// Convert String to Vec
let _s = s.into_bytes();
s
}
I have gotten through. My solution works.
However, when I compile the exercise code-snippet above unchanged, I don't quite get what the compiler is telling me here, as a note below:
Compiling playground v0.0.1 (/playground)
error[E0382]: use of moved value: `s`
--> src/main.rs:12:5
|
9 | let s = String::from("hello, world");
| - move occurs because `s` has type `String`, which does not implement the `Copy` trait
10 | // Convert String to Vec
11 | let _s = s.into_bytes();
| ------------ `s` moved due to this method call
12 | s
| ^ value used here after move
|
note: this function takes ownership of the receiver `self`, which moves `s`
My guess is that the note is about the function into_bytes(). The RustDoc says this about the function:
This consumes the String, so we do not need to copy its contents.
Could someone please elaborate on this?
into_bytes() takes self (i.e. an owned self, not a reference).
This means that it takes ownership of the string it's called on. It's conceptually the same as this:
fn main() {
let s = String::from("hello");
take_string(s);
println!("{s}"); // ERROR
}
fn take_string(s: String) {}
This is useful because it allows you to turn a String into a Vec<u8>, while reusing the allocation. A String is really just a Vec<u8> with the guarantee that the bytes are valid UTF-8.
So once you write let _s = s.into_bytes(), the data that was in s has now moved to _s, so you can't return s from your function. There's nothing there.
If you just want to return the string, you can just return String::from("stuff")

Create a slice of slice with sufficient lifetime

I have a function foo that takes in parameter an array slice of array slices, however I can't seem to create a variable that lives long enough to pass it as a parameter:
fn main() {
let mut outer_vec = vec![];
for i in 0..10 {
let inner_vec = vec![i];
outer_vec.push(inner_vec.as_slice());
}
foo(&outer_vec);
}
fn foo(_bar: &[&[u8]]) {
println!("foo");
}
I get this error:
error[E0597]: `inner_vec` does not live long enough
--> src/main.rs:5:24
|
5 | outer_vec.push(inner_vec.as_slice());
| ^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
6 | }
| - `inner_vec` dropped here while still borrowed
7 | foo(&outer_vec);
| ---------- borrow later used here
I know that a given inner array slice cannot outlive the lifetime of the inner_vec it originates from, which is dropped at the end of the for loop, but I want to know if it is possible to fix this error without changing the signature of the foo function, that is, keep it foo(_bar: &[&[u8]]) and not change it to something like foo(_bar: &[Vec<u8>]).
Thank you for your help.
Your problem has nothing to do with function foo. It exists inside for loop. Comment out calling foo and you will still have an error. In every iteration you create local variable inner_vec that is dropped at the end of the iteration. You therefore cannot store a reference to it that would escape the for loop. In other words it's lifetime is to short.
The solution here would be to give the ownership of inner_vec to outer_vec by moving it (not the reference). Then you would have to change foo's signature as well.
To keep the same signature for foo, you can create a variable that keeps the ownership of the inner_vecs and create slices from it in another variable:
fn main() {
let mut outer_vec = vec![];
for i in 0..10 {
let inner_vec = vec![i];
outer_vec.push(inner_vec);
}
let vec_of_slices: Vec<&[u8]> = outer_vec.iter()
.map(|inner_vec| inner_vec.as_slice()).collect();
foo(&vec_of_slices);
}
fn foo(_bar: &[&[u8]]) {
println!("foo");
}

Why does a variable holding the result of Vec::get_mut not need to be mutable?

I have the following code:
fn main() {
let mut vec = Vec::new();
vec.push(String::from("Foo"));
let mut row = vec.get_mut(0).unwrap();
row.push('!');
println!("{}", vec[0])
}
It prints out "Foo!", but the compiler tells me:
warning: variable does not need to be mutable
--> src/main.rs:4:9
|
4 | let mut row = vec.get_mut(0).unwrap();
| ----^^^
| |
| help: remove this `mut`
Surprisingly, removing the mut works. This raises a few questions:
Why does this work?
Why doesn't this work when I use vec.get instead of vec.get_mut, regardless of whether I use let or let mut?
Why doesn't vec work in the same way, i.e. when I use let vec = Vec::new(), why can't I call vec.push()?
vec.get_mut(0) returns an Option<&mut String>, so when you unwrap that value you will have a mutable borrow of a String. Remember, that a let statement's left side is using pattern matching, so when your pattern is just a variable name you essentially say match whatever is on the right and call it name. Thus row matches against &mut String so it already is mutable.
Here's a much simpler and more straightforward example to illustrate the case (which you can try in the playground):
fn main() {
let mut x = 55i32;
dbg!(&x);
let y = &mut x; // <-- y's type is `&mut i32`
*y = 12;
dbg!(&x);
}

How to push a value to a Vec and append it to a String at the same time?

I want to write a program that sets the shell for the system's nslookup command line program:
fn main() {
let mut v: Vec<String> = Vec::new();
let mut newstr = String::from("nslookup");
for arg in std::env::args() {
v.push(arg);
newstr.push_str(&format!(" {}", arg));
}
println!("{:?}", v);
println!("{}", newstr);
}
error[E0382]: borrow of moved value: `arg`
--> src/main.rs:6:41
|
5 | v.push(arg);
| --- value moved here
6 | newstr.push_str(&format!(" {}", arg));
| ^^^ value borrowed here after move
|
= note: move occurs because `arg` has type `std::string::String`, which does not implement the `Copy` trait
How to correct the code without traversing env::args() again?
Reverse the order of the lines that use arg:
for arg in std::env::args() {
//newstr.push_str(&format!(" {}", arg));
write!(&mut newstr, " {}", arg);
v.push(arg);
}
Vec::push takes its argument by value, which moves ownership of arg so it can't be used anymore after v.push(arg). format! and related macros implicitly borrow their arguments, so you can use arg again after using it in one of those.
If you really needed to move the same String to two different locations, you would need to add .clone(), which copies the string. But that's not necessary in this case.
Also note that format! creates a new String, which is wasteful when all you want is to add on to the end of an existing String. If you add use std::fmt::Write; to the top of your file, you can use write! instead (as shown above), which is more concise and may be more performant.
See also
What are move semantics in Rust?
error: use of moved value - should I use "&" or "mut" or something else?
Does println! borrow or own the variable?
You can do like that:
fn main() {
let args: Vec<_> = std::env::args().collect();
let s = args.join(" ");
println!("{}", s);
}
First, you create the vector, and then you create your string.

What does "cannot move out of index of" mean?

I am playing with Rust, and I'm trying to access the first command line argument with this code:
use std::env;
fn main() {
let args: Vec<_> = env::args().collect();
let dir = args[1];
}
And I get this error:
error[E0507]: cannot move out of indexed content
--> src/main.rs:5:15
|
5 | let dir = args[1];
| --- ^^^^^^^ cannot move out of indexed content
| |
| hint: to prevent move, use `ref dir` or `ref mut dir`
Or in later versions of Rust:
error[E0507]: cannot move out of index of `std::vec::Vec<std::string::String>`
--> src/main.rs:5:15
|
5 | let dir = args[1];
| ^^^^^^^
| |
| move occurs because value has type `std::string::String`, which does not implement the `Copy` trait
| help: consider borrowing here: `&args[1]`
If I change it to let ref dir, it compiles, but I don't grok what's going on. Could someone explain what "indexed content" means?
When you use an index operator ([]) you get the actual object at index location. You do not get a reference, pointer or copy. Since you try to bind that object with a let binding, Rust immediately tries to move (or copy, if the Copy trait is implemented).
In your example, env::args() is an iterator of Strings which is then collected into a Vec<String>. This is an owned vector of owned strings, and owned strings are not automatically copyable.
You can use a let ref binding, but the more idiomatic alternative is to take a reference to the indexed object (note the & symbol):
use std::env;
fn main() {
let args: Vec<_> = env::args().collect();
let ref dir = &args[1];
// ^
}
Implicitly moving out of a Vec is not allowed as it would leave it in an invalid state — one element is moved out, the others are not. If you have a mutable Vec, you can use a method like Vec::remove to take a single value out:
use std::env;
fn main() {
let mut args: Vec<_> = env::args().collect();
let dir = args.remove(1);
}
See also:
What is the return type of the indexing operation?
For your particular problem, you can also just use Iterator::nth:
use std::env;
fn main() {
let dir = env::args().nth(1).expect("Missing argument");
}
The accepted answer has already given the solution. I would like to explain this problem on a semantic level as a complement.
The rule is: A borrowed value can't be moved out. See this: E0507
[] operator came from the Index trait, whose function signature is:
fn index(&self, index: I) -> &<Vec<T, A> as Index<I>>::Output
As you can see, it return a reference, not own the value. Moving it out break the rule mentioned above.

Resources