Currently my code looks like this:
use std::process::Command;
use std::str;
fn main() {
let result_version = Command::new("git")
.arg("--version")
.output()
.unwrap();
let rc_version = result_version.status;
println!("{}", rc_version);
let mut stdout_version = str::from_utf8(&result_version.stdout).unwrap().to_string();
let stdout_version_trimmed= trim_newline(stdout_version);
println!("'{}'", stdout_version_trimmed);
}
fn trim_newline(s: &mut String) {
if s.ends_with('\n') {
s.pop();
if s.ends_with('\r') {
s.pop();
}
}
}
But unfortunately the compiler gives me:
error[E0308]: mismatched types
--> src/main.rs:15:46
|
15 | let stdout_version_trimmed= trim_newline(stdout_version);
| ^^^^^^^^^^^^^^
| |
| expected `&mut std::string::String`, found struct `std::string::String`
| help: consider mutably borrowing here: `&mut stdout_version`
So after the comment of mcarton I realised that the trim_newline does not return the changed string it is just changing it.
So the final result is this which compiles error free without any warning.
use std::process::Command;
use std::str;
fn main() {
let result_version = Command::new("git")
.arg("--version")
.output()
.unwrap();
let rc_version = result_version.status;
println!("{}", rc_version);
let mut stdout_version = str::from_utf8(&result_version.stdout).unwrap().to_string();
trim_newline(&mut stdout_version);
println!("'{}'", stdout_version);
}
fn trim_newline(s: &mut String) {
if s.ends_with('\n') {
s.pop();
if s.ends_with('\r') {
s.pop();
}
}
}
Related
I have a function to reverse characters in words and I need to know how to convert a Vec<&String> into a regular owned String (with spaces between the words).
fn reverse_words(words: &str) -> String {
let mut split = words.split_whitespace();
let vec: Vec<&str> = split.collect();
let vec2 = vec!();
for word in vec {
vec2.push(&word.chars().rev().collect::<String>());
}
return vec2;
}
.
error[E0308]: mismatched types
--> src/lib.rs:8:12
|
1 | fn reverse_words(words: &str) -> String {
| ------ expected `String` because of return type
...
8 | return vec2;
| ^^^^ expected struct `String`, found struct `Vec`
|
= note: expected struct `String`
found struct `Vec<&String>`
For more information about this error, try `rustc --explain E0308`.
error: could not compile `challenge` due to previous error
NOTE: Line numbers in error messages can be incorrect due to concatenation.
Here is a version of your code with minimal changes to make it work. You basically only need to add a .join(' ') to your last statement:
fn reverse_words(words: &str) -> String {
let split = words.split_whitespace();
let vec: Vec<&str> = split.collect();
let mut vec2 = vec![];
for word in vec {
vec2.push(word.chars().rev().collect::<String>());
}
vec2.join(" ")
}
fn main() {
let sentence = "hello world";
assert_eq!(reverse_words(sentence), "olleh dlrow");
}
Playground.
This is an inefficient implementation requiring a lot of allocation though. You can chain methods of the Iterator trait to get a solution that does not require as much allocation:
fn reverse_words(words: &str) -> String {
words
.split_whitespace()
.map(|w| w.chars().rev().chain([' ']))
.flatten()
.take(words.len())
.collect::<String>()
}
fn main() {
let sentence = "hello world";
assert_eq!(reverse_words(sentence), "olleh dlrow");
}
Playground.
I am learning Rust and playing with Tokio, channels and Serde. I am having difficulty writing some very basic code:
use serde::{Deserialize, Serialize};
use tokio::sync::mpsc::{channel, Receiver};
struct WorkflowProcess {
rx: Receiver<String>,
}
#[derive(Deserialize, Serialize)]
struct Msg {
version: i32,
}
impl WorkflowProcess {
async fn process<'a, T: Deserialize<'a>>(&mut self, callback: impl Fn(T)) {
let r = self.rx.recv().await;
if let Some(v) = r {
let s: &str = v.as_str();
let deserialized: T = serde_json::from_str(s).unwrap();
callback(deserialized);
}
}
}
#[tokio::main]
async fn main() {
let (tx, rx) = channel::<String>(100);
let mut workflow = WorkflowProcess { rx };
let worker = tokio::spawn(async move {
let x = |msg: Msg| {
assert_eq!(
msg.version,
32
);
};
workflow.process(x).await;
});
let serialized = serde_json::to_string(&Msg { version: 32 }).unwrap();
tx.send(serialized).await;
worker.await;
}
Trying to compile gives me this error:
error[E0597]: `v` does not live long enough
--> src/main.rs:17:27
|
14 | async fn process<'a, T: Deserialize<'a>>(&mut self, callback: impl Fn(T)) {
| -- lifetime `'a` defined here
...
17 | let s: &str = v.as_str();
| ^^^^^^^^^^ borrowed value does not live long enough
18 | let deserialized: T = serde_json::from_str(s).unwrap();
| ----------------------- argument requires that `v` is borrowed for `'a`
19 | callback(deserialized);
20 | }
| - `v` dropped here while still borrowed
It seems to me the deserialized lifetime falls within the lifetime of v and s, but I am guessing 'a is not what I think it is. I wish there was a lifetime debugger/visualizer for Rust. Is 'a same as 'static in this case?
I know I can use DeserializeOwned, but I really wanted to get to the bottom of my misunderstanding.
You can use HRTB as #Jmb suggested in the comments:
impl WorkflowProcess {
async fn process<T>(&mut self, callback: impl Fn(T))
where
for<'a> T: Deserialize<'a>,
{
let r = self.rx.recv().await;
if let Some(v) = r {
let deserialized: T = {
let s: &str = v.as_str();
serde_json::from_str(s).unwrap()
};
callback(deserialized);
}
}
}
Playground
A simple program, what I am trying to do is get lines from a file, or if the file is not present, pass in a zero-length iterator:
use std::fs::File;
use std::io::{self, BufRead};
fn run_against_input(inp: &mut dyn Iterator<Item = String>) {
for i in inp {
println!("Input line: {}", i);
}
}
fn main() {
let file = File::open("data.txt");
let input: dyn Iterator<Item = String> = match file {
Ok(f) => io::BufReader::new(f).lines()
.map(|line| line.unwrap()),
Err(_) => Vec::new().into_iter()
};
run_against_input(&mut dyn input);
}
When I do this, I get the following error:
Compiling playground v0.0.1 (/playground)
error: expected expression, found keyword `dyn`
--> src/main.rs:19:28
|
19 | run_against_input(&mut dyn input);
| ^^^ expected expression
error[E0308]: mismatched types
--> src/main.rs:13:18
|
13 | Ok(f) => io::BufReader::new(f).lines()
| __________________^
14 | | .map(|line| line.unwrap()),
| |______________________________________^ expected trait object `dyn Iterator`, found struct `Map`
|
= note: expected trait object `dyn Iterator<Item = String>`
found struct `Map<std::io::Lines<BufReader<File>>, [closure#src/main.rs:14:18: 14:38]>`
For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to 2 previous errors
I do specifically need a &mut reference to the Iterator in the code I am writing (this is a small reproduction of the problem that I am facing), but I guess that has nothing to do with the issue at hand. I see that there is an impl on Iterator for Map, but the error I get is that this is not the trait object for Iterator<Item = String>. I also tried this:
let input: &mut dyn Iterator<Item = String> = match file {
Ok(f) => &mut io::BufReader::new(f).lines()
.map(|line| line.unwrap()),
Err(_) => &mut Vec::new().into_iter()
};
which of course didn't work, since the temporary value is being dropped in the statement to which I am returning a reference (which is why I did the let binding thing as the compiler suggested).
EDIT Link to playground - https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=99b8105ecc266e03db2d92cc22610962
You can hold the iterators for each branch in a separate variable outside the match (and also use std::iter::empty() instead of Vec::new().into_iter()):
use std::fs::File;
use std::io::{self, BufRead};
use std::iter;
fn run_against_input(inp: impl Iterator<Item = String>) {
for i in inp {
println!("Input line: {}", i);
}
}
fn main() {
let file = File::open("data.txt");
let mut lines;
let mut no_lines;
let input: &mut dyn Iterator<Item = String> = match file {
Ok(f) => {
lines = io::BufReader::new(f).lines().map(Result::unwrap);
&mut lines
},
Err(_) => {
no_lines = iter::empty();
&mut no_lines
},
};
run_against_input(input);
}
You can use a Box instead of a reference, so the value is owned and won't be dropped:
let mut input: Box<dyn Iterator<Item = String>> = match file {
Ok(f) => Box::new(io::BufReader::new(f).lines().map(|line| line.unwrap())),
Err(_) => Box::new(Vec::new().into_iter()),
};
playground
If you prefer you could also change your function to take a Box instead of a reference:
fn run_against_input(inp: Box<dyn Iterator<Item = String>>) {
I have an Option<T> that is shared by several structures and that must be mutable. I'm using a RefCell since, as I understand, it is the tool for that job. How do I access (and alter) the content of that Option<T> ?
I tried the following:
use std::cell::RefCell;
#[derive(Debug)]
struct S {
val: i32
}
fn main() {
let rc: RefCell<Option<S>> = RefCell::new(Some(S{val: 0}));
if let Some(ref mut s2) = rc.borrow_mut() {
s2.val += 1;
}
println!("{:?}", rc);
}
But the compiler won't let me do it:
error[E0308]: mismatched types
--> <anon>:10:12
|
10 | if let Some(ref mut s2) = rc.borrow_mut() {
| ^^^^^^^^^^^^^^^^ expected struct `std::cell::RefMut`, found enum `std::option::Option`
|
= note: expected type `std::cell::RefMut<'_, std::option::Option<S>, >`
found type `std::option::Option<_>`
When you borrow_mut the RefCell, you get a RefMut, as the compiler says. To get the value inside it, just use the operator deref_mut:
use std::cell::RefCell;
#[derive(Debug)]
struct S {
val: i32
}
fn main() {
let rc: RefCell<Option<S>> = RefCell::new(Some(S{val: 0}));
if let Some(ref mut s2) = *rc.borrow_mut() { // deref_mut
s2.val += 1;
}
println!("{:?}", rc);
}
I want to use the write_fmt method on two different types of object:
use std::fmt::Write;
use std::io::Write;
fn main() {
let mut a = String::new();
let mut b = std::fs::File::create("test").unwrap();
a.write_fmt(format_args!("hello"));
b.write_fmt(format_args!("hello"));
}
I get an error when using Write because they are both named the same:
error[E0252]: a trait named `Write` has already been imported in this module
--> src/main.rs:8:5
|
7 | use std::fmt::Write;
| --------------- previous import of `Write` here
8 | use std::io::Write;
| ^^^^^^^^^^^^^^ `Write` already imported
a.write_fmt(format_args!("hello"));
b.write_fmt(format_args!("hello"));
Or I get an error saying the trait is not available:
error[E0599]: no method named `write_fmt` found for type `std::fs::File` in the current scope
--> src/main.rs:76:4
|
76 | b.write_fmt(format_args!("hello"));
| ^^^^^^^^^
|
= help: items from traits can only be used if the trait is in scope; the following trait is implemented but not in scope, perhaps add a `use` for it:
= help: candidate #1: `use std::io::Write;`
You can call the trait method directly:
fn main() {
let mut a = String::new();
let mut b = std::fs::File::create("test").unwrap();
std::fmt::Write::write_fmt(&mut a, format_args!("hello"));
std::io::Write::write_fmt(&mut b, format_args!("hello"));
}
You can also choose to only import the trait in a smaller scope:
fn main() {
let mut a = String::new();
let mut b = std::fs::File::create("test").unwrap();
{
use std::fmt::Write;
a.write_fmt(format_args!("hello"));
}
{
use std::io::Write;
b.write_fmt(format_args!("hello"));
}
}
Note that if you choose to use a smaller scope, you can also use the write! macro directly:
fn main() {
let mut a = String::new();
let mut b = std::fs::File::create("test").unwrap();
{
use std::fmt::Write;
write!(a, "hello");
}
{
use std::io::Write;
write!(b, "hello");
}
}
In either case, you should handle the Result return value.
See also:
How to call a method when a trait and struct use the same name?
You can specify an alias for use:
use std::fmt::Write as FmtWrite;
use std::io::Write;
fn main() {
let mut a = String::new();
let mut b = std::fs::File::create("test").unwrap();
a.write_fmt(format_args!("hello"));
b.write_fmt(format_args!("hello"));
}
If you just want to call the traits method, you can even just bring them in scope:
use std::fmt::Write as _;
use std::io::Write as _;
fn main() {
let mut a = String::new();
let mut b = std::fs::File::create("test").unwrap();
a.write_fmt(format_args!("hello"));
b.write_fmt(format_args!("hello"));
}
Be careful, this solution works when different types implement different traits with the same name. If the same type implements different traits with the same name, you must use Shepmaster's answer:
mod foo {
pub trait Trait {
fn do_something(&self) {}
}
}
mod bar {
pub trait Trait {
fn do_something(&self) {}
}
}
pub struct Concrete {}
impl foo::Trait for Concrete {}
impl bar::Trait for Concrete {}
fn main() {
let x = Concrete {};
{
use foo::Trait; // use limited to scope
x.do_something(); // call foo::Trait::do_something
}
{
foo::Trait::do_something(&x); // complete path to disambiguate
bar::Trait::do_something(&x); // complete path to disambiguate
}
{
use foo::Trait as FooTrait;
use bar::Trait;
x.do_something(&x); // ERROR: multiple applicable items in scope
}
}