Converting a Vec<&str> to Vec<&CStr> in rust - rust

Take a look at this function:
fn exec(cli: Vec<&str>) {
eprintln!("execing: {:?}", cli);
let args: Vec<&CStr> = cli.iter()
.map(|s| CString::new(s.as_bytes()).unwrap().as_c_str())
.collect();
execv(args[0], &args);
debug(args);
}
It takes a Vec<&str> and executes it as a command. I'm having trouble converting this to Vec<&CStr> (which is what execv needs). Compiler reports this error for the map operations:
error[E0515]: cannot return value referencing temporary value
--> src/idea.rs:141:18
|
141 | .map(|s| CString::new(s.as_bytes()).unwrap().as_c_str())
| -----------------------------------^^^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| temporary value created here
How do I fix this error?

You have to collect all CString to a separated vector so you references will be valid during execv call:
use std::ffi::CString;
use std::ffi::CStr;
fn main() {
let cli = vec!["hello", "world"];
let vec: Vec<_> = cli.iter()
.map(|s| CString::new(s.as_bytes()).unwrap())
.collect();
let vec_obj: Vec<&CStr> = vec.iter().map(|c| c.as_c_str()).collect();
println!("CString:{:?}", vec);
println!("&CStr:{:?}", vec_obj);
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c440ea898abe2ed5573993923ee6b74f

Related

Use of moved value `inb`

I'm trying to write a function, and I'm getting an error message about borrowing that I can't solve because I'm struggling to wrap my head around other responses on this site. Here's the function I've got so far:
use orgize::Org;
fn convert(i: String) -> String {
let inb: Vec<u8> = Vec::new();
Org::parse_string(i).write_html(inb);
let out = String::from_utf8(inb).unwrap();
return out;
}
And it's outputting the following error:
error[E0382]: use of moved value: `inb`
--> src/main.rs:9:30
|
7 | let inb: Vec<u8> = Vec::new();
| --- move occurs because `inb` has type `Vec<u8>`, which does not implement the `Copy` trait
8 | Org::parse_string(i).write_html(inb);
| --- value moved here
9 | let out = String::from_utf8(inb).unwrap();
| ^^^ value used here after move
When you call write_html(inb), you are moving inb. It cannot be used anymore.
Since write_html() accepts a generic W: Write, and Vec<u8> implements Write but also any &mut Write implements Write, you can just pass &mut inb to borrow inb instead of moving it:
fn convert(i: String) -> String {
let mut inb: Vec<u8> = Vec::new();
Org::parse_string(i).write_html(&mut inb);
let out = String::from_utf8(inb).unwrap();
return out;
}

Resolving borrowed value issue

I have the following simple code. I am not able to figure out how to resolve the error "borrowed value does not live long enough".
fn main() {
let mut saved_message: Vec<&str> = Vec::new();
for i in 0..10 {
let mut tmp: String = String::from("line_num ");
tmp.push_str(&i.to_string());
saved_message.push(&tmp);
}
}
Compiling rust_test v0.1.0 (C:\workspace\rust_test)
error[E0597]: `tmp` does not live long enough
--> src\lib.rs:6:28
|
6 | saved_message.push(&tmp);
| -------------------^^^^-
| | |
| | borrowed value does not live long enough
| borrow later used here
7 | }
| - `tmp` dropped here while still borrowed
For more information about this error, try `rustc --explain E0597`.
error: could not compile `rust_test` due to previous error
Error comes from this line:
let mut saved_message: Vec<&str> = Vec::new();
Here, you defined a vector of references to string slices.
Since you are storing references instead of the whole string, every reference that is stored in the vector, should outlive the vector itself. But this is not the case with your code as each tmp value in your for loop gets droped at the end of the loop (reference is no longer valid) and thus, pushing it to a vector that would outlive the for loop is not safe.
workarounds:
Create a vector of String instead of &str
fn main() {
let mut saved_message: Vec<String> = Vec::new();
for i in 0..10 {
let mut tmp: String = String::from("line_num ");
tmp.push_str(&i.to_string());
saved_message.push(tmp);
}
}
Notice the vector type hint which is now Vec<String> instead of Vec<&str>.
Note that now you should push tmp instead of &tmp in the last line.
You can also trust the compiler to guess the type for you and remove the whole type hint:
fn main() {
let mut saved_message = Vec::new();
for i in 0..10 {
let mut tmp = String::from("line_num ");
tmp.push_str(&i.to_string());
saved_message.push(tmp);
}
}

What's the difference between var and _var in Rust?

Given this:
fn main() {
let variable = [0; 15];
}
The Rust compiler produces this warning:
= note: #[warn(unused_variables)] on by default
= note: to avoid this warning, consider using `_variable` instead
What's the difference between variable and _variable?
The difference is an underscore at the front, which causes the Rust compiler to allow it to be unused. It is kind of a named version of the bare underscore _ which can be used to ignore a value.
However, _name acts differently than _. The plain underscore drops the value immediately while _name acts like any other variable and drops the value at the end of the scope.
An example of how it does not act exactly the same as a plain underscore:
struct Count(i32);
impl Drop for Count {
fn drop(&mut self) {
println!("dropping count {}", self.0);
}
}
fn main() {
{
let _a = Count(3);
let _ = Count(2);
let _c = Count(1);
}
{
let _a = Count(3);
let _b = Count(2);
let _c = Count(1);
}
}
prints the following (playground):
dropping count 2
dropping count 1
dropping count 3
dropping count 1
dropping count 2
dropping count 3
The key difference between _variable and variable is that first one tells compiler not to give any warnings if we do not use it in our code. Example:
// src/main.rs
fn main() {
let _x = 1;
let y = 2;
}
Compiling main.rs gives:
warning: unused variable: `y`
--> src/main.rs:3:9
|
3 | let y = 2;
| ^ help: if this is intentional, prefix it with an underscore: `_y`
|
= note: `#[warn(unused_variables)]` on by default
The more interesting case is when we are comparing _ with _variable.
Ignoring an Unused Variable by Starting Its Name with _:
The syntax _x still binds the value to the variable, whereas _ doesn’t bind at all.
Consider example:
// src/main.rs
fn main() {
let s = Some(String::from("Hello!"));
if let Some(_s) = s {
println!("found a string");
}
println!("{:?}", s);
}
When we try to compile main.rs we get error:
error[E0382]: borrow of moved value: `s`
--> src/main.rs:8:22
|
4 | if let Some(_s) = s {
| -- value moved here
...
8 | println!("{:?}", s);
| ^ value borrowed here after partial move
|
= note: move occurs because value has type `std::string::String`, which does not implement the `Copy` trait
help: borrow this field in the pattern to avoid moving `s.0`
|
4 | if let Some(ref _s) = s {
| ^^^
Aha! The syntax _x still binds the value to the variable, which means that we are moving the ownership of s to _s, thus, we can no longer access variable s anymore; which happens when we try to print value of s.
The correct way of doing the above is:
// src/main.rs
fn main() {
let s = Some(String::from("Hello!"));
if let Some(_) = s {
println!("found a string");
}
println!("{:?}", s);
}
Above code works just fine. s does not get moved into _, so we can still access it later.
Sometimes I use _ with iterators:
fn main() {
let v = vec![1, 2, 3];
let _ = v
.iter()
.map(|x| {
println!("{}", x);
})
.collect::<Vec<_>>();
}
Compiling gives result:
1
2
3
When doing more complex operations on iterable types above example acts as utility for me.

Rust File examples don't compile [duplicate]

This question already has answers here:
Why do try!() and ? not compile when used in a function that doesn't return Option or Result?
(4 answers)
Closed 5 years ago.
The Rust file examples don't appear compile with Rust 1.18.0.
For example:
use std::fs::File;
use std::io::prelude::*;
fn main() {
let mut file = File::open("foo.txt")?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
assert_eq!(contents, "Hello, world!");
}
Error log:
rustc 1.18.0 (03fc9d622 2017-06-06)
error[E0277]: the trait bound `(): std::ops::Carrier` is not satisfied
--> <anon>:4:20
|
4 | let mut file = File::open("foo.txt")?;
| ----------------------
| |
| the trait `std::ops::Carrier` is not implemented for `()`
| in this macro invocation
|
= note: required by `std::ops::Carrier::from_error`
error[E0277]: the trait bound `(): std::ops::Carrier` is not satisfied
--> <anon>:6:5
|
6 | file.read_to_string(&mut contents)?;
| -----------------------------------
| |
| the trait `std::ops::Carrier` is not implemented for `()`
| in this macro invocation
|
= note: required by `std::ops::Carrier::from_error`
error: aborting due to 2 previous errors
? is a syntactic sugar that checks a Result: if the result is Err, it is returned as if. If there is no error (aka Ok), the function continue. When you type this:
fn main() {
use std::fs::File;
let _ = File::open("foo.txt")?;
}
that means:
fn main() {
use std::fs::File;
let _ = match File::open("foo.txt") {
Err(e) => return Err(e),
Ok(val) => val,
};
}
Then you understand that for now, you cannot use ? in the main, because main returns unit () and not Result. If you want this stuff to work, you can put it in a function that returns a Result and check it from main:
fn my_stuff() -> std::io::Result<()> {
use std::fs::File;
use std::io::prelude::*;
let mut file = File::open("foo.txt")?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
// do whatever you want with `contents`
Ok(())
}
fn main() {
if let Err(_) = my_stuff() {
// manage your error
}
}
PS: There is a proposition to make work ? in the main.
They do compile. They just don't compile in a main function like that. If you look at the examples, they all have a big "Run" button on them. Click that and it opens the full, unabridged example on the playpen.
The one you've used above expands to this code:
fn main() {
use std::fs::File;
use std::io::prelude::*;
fn foo() -> std::io::Result<()> {
let mut file = File::open("foo.txt")?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
assert_eq!(contents, "Hello, world!");
Ok(())
}
}
That code doesn't compile because you've put code that propagates a Result into a function (main in this case) that doesn't return a Result.

How to destructure tuple struct with reference

I'm trying to use the hyper library to make some requests. The Headers::get() method returns Option<&H>, where H is a tuple struct with one field. I can use if let Some() to destructure the Option. But how do we destructure the &H? Sure I could always access the field with .0, but I'm curious if Rust has a syntax to do this.
struct s(String);
fn f(input: &s) -> &s {
input
}
fn main() {
let my_struct1 = s("a".to_owned());
let s(foo) = my_struct1;
let my_struct2 = s("b".to_owned());
let &s(bar) = f(&my_struct2); // this does not work
let baz = &my_struct2.0; // this works
}
When you try to compile this, the Rust compiler will tell you how to fix the error with a nice message:
error[E0507]: cannot move out of borrowed content
--> <anon>:11:9
|
11 | let &s(bar) = f(&my_struct2); // this does not work
| ^^^---^
| | |
| | hint: to prevent move, use `ref bar` or `ref mut bar`
| cannot move out of borrowed content
This is needed to tell the compiler that you only want a reference to the field in the struct; the default matching will perform a move and the original struct value will no longer be valid.
Let's fix the example:
struct s(String);
fn f(input: &s) -> &s {
input
}
fn main() {
let my_struct1 = s("a".to_owned());
let s(foo) = my_struct1;
let my_struct2 = s("b".to_owned());
let &s(ref bar) = f(&my_struct2);
}
Another way is to dereference first and drop the &. I think this is preferred in Rust:
struct s(String);
fn f(input: &s) -> &s {
input
}
fn main() {
let my_struct1 = s("a".to_owned());
let s(foo) = my_struct1;
let my_struct2 = s("b".to_owned());
let s(ref bar) = *f(&my_struct2);
}

Resources