With this code:
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
#[arg(short, long, default_value_t = ("/dev/ttyUSB3".to_string()))]
modem_path: String,
...
}
I get a warning:
warning: unnecessary parentheses around assigned value
--> src/main.rs:30:42
|
30 | #[arg(short, long, default_value_t = ("/dev/ttyUSB3".to_string()))]
| ^ ^
|
= note: `#[warn(unused_parens)]` on by default
help: remove these parentheses
|
30 - #[arg(short, long, default_value_t = ("/dev/ttyUSB3".to_string()))]
30 + #[arg(short, long, default_value_t = "/dev/ttyUSB3".to_string())]
|
If I remove the parens, I get an error:
error: expected `,`
--> src/main.rs:30:56
|
30 | #[arg(short, long, default_value_t = "/dev/ttyUSB3".to_string())]
| ^
I have many other more complex arguments with the same issue, e.g.
#[arg(short, long, default_value_t = ("127.0.0.1:2947".parse().unwrap()))]
gpsd_socket: SocketAddr,
How can I make this code error- and warning-free?
It's hard to judge whether this is a bug of rustc (warning in macros even when this is incorrect) or of clap (expanding to a code including unnecessary parentheses) but this is definitely not your fault. Unfortunately, it seems the best you can do is to #[allow(unused_parens)] for the whole module. You can separate the struct into a different module to minimize the impact:
#[allow(unused_parens)]
mod args {
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub(super) struct Args {
#[arg(short, long, default_value_t = ("/dev/ttyUSB3".to_string()))]
pub(super) modem_path: String,
// ...
}
}
Related
I'm trying out the "Using Derive Macros" example on the index page for the latest beta version of clap:
// (Full example with detailed comments in examples/01d_quick_example.rs)
//
// This example demonstrates clap's full 'custom derive' style of creating arguments which is the
// simplest method of use, but sacrifices some flexibility.
use clap::{AppSettings, Parser};
/// This doc string acts as a help message when the user runs '--help'
/// as do all doc strings on fields
#[derive(Parser)]
#[clap(version = "1.0", author = "Kevin K. <kbknapp#gmail.com>")]
struct Opts {
/// Sets a custom config file. Could have been an Option<T> with no default too
#[clap(short, long, default_value = "default.conf")]
config: String,
/// Some input. Because this isn't an Option<T> it's required to be used
input: String,
/// A level of verbosity, and can be used multiple times
#[clap(short, long, parse(from_occurrences))]
verbose: i32,
#[clap(subcommand)]
subcmd: SubCommand,
}
...
Unfortunately it fails to compile:
$ cargo build
Compiling ex v1.0.0-SNAPSHOT (/home/hwalters/git/home/ex)
error: cannot find derive macro `Parser` in this scope
--> src/main.rs:5:10
|
5 | #[derive(Parser)]
| ^^^^^^
|
note: `Parser` is imported here, but it is only a trait, without a derive macro
--> src/main.rs:1:25
|
1 | use clap::{AppSettings, Parser};
| ^^^^^^
error: cannot find attribute `clap` in this scope
--> src/main.rs:6:3
|
6 | #[clap(version = "1.0", author = "Kevin K. <kbknapp#gmail.com>")]
| ^^^^
|
= note: `clap` is in scope, but it is a crate, not an attribute
...
I tried to find the full example file "examples/01d_quick_example.rs" in the tar file for this GitHub tag, but it does not seem exist there.
I appreciate this is a beta version, but is this functionality expected to work, or am I doing something wrong?
Thanks!
In clap, use features = [ "derive" ] in Cargo.toml to enable the ability to derive :)
update
#stein below makes a good point of expanding the answer:
To "use" means: in the [dependencies] section, specify clap with a
line similar to: clap = { version = "3.1.0", features = ["derive"]} –
Stein Feb 19 at 13:00
Please +1 their comment :-).
This means, in your Cargo.toml
[dependencies]
# ...
clap = { version = "3", features = ["derive"]}
I'm running through some LeetCode challenges to build up my understanding of Rust. I'm trying to write the following program that takes an i32 input, converts it to a String, reverses the digits, and returns back an i32 number.
In the case of negative numbers, e.g. -132, when the number is reversed the hyphen has to be popped off the stack: -132 -> 231- -> 231.
I've written the following code but I'm bumping up against the borrow checker, can anyone help?
impl Solution {
pub fn reverse(x: i32) -> i32 {
if(x == 0){
return x;
}
let reversed : std::iter::Rev<std::str::Chars> = x.to_string().chars().rev();
if reversed.last().unwrap() == '-' { //error occurs here
return reversed.collect::<String>()[0..reversed.count()].parse::<i32>().unwrap();
} else {
return reversed.collect::<String>().parse::<i32>().unwrap();
}
}
}
Line 6, Char 61: temporary value dropped while borrowed (solution.rs)
|
6 | let reversed : &std::iter::Rev<std::str::Chars> = &x.to_string().chars().rev();
| ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
7 | if reversed.last().unwrap() == '-' {
| -------- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
Line 7, Char 12: cannot move out of `*reversed` which is behind a shared reference (solution.rs)
|
7 | if reversed.last().unwrap() == '-' {
| ^^^^^^^^ move occurs because `*reversed` has type `std::iter::Rev<std::str::Chars<'_>>`, which does not implement the `Copy` trait
Line 8, Char 20: cannot move out of `*reversed` which is behind a shared reference (solution.rs)
|
8 | return reversed.collect::<String>()[0..reversed.count()].parse::<i32>().unwrap();
| ^^^^^^^^ move occurs because `*reversed` has type `std::iter::Rev<std::str::Chars<'_>>`, which does not implement the `Copy` trait
Line 8, Char 52: cannot move out of `*reversed` which is behind a shared reference (solution.rs)
|
8 | return reversed.collect::<String>()[0..reversed.count()].parse::<i32>().unwrap();
| ^^^^^^^^ move occurs because `*reversed` has type `std::iter::Rev<std::str::Chars<'_>>`, which does not implement the `Copy` trait
Line 10, Char 20: cannot move out of `*reversed` which is behind a shared reference (solution.rs)
|
10 | return reversed.collect::<String>().parse::<i32>().unwrap();
| ^^^^^^^^ move occurs because `*reversed` has type `std::iter::Rev<std::str::Chars<'_>>`, which does not implement the `Copy` trait
Here's the error reproduced in a playground
Original error reproduced in this playground
Here's a solution that is close to your approach that fixes the error:
fn reverse(x: i32) -> i32 {
if x == 0 {
return x;
}
let mut reversed:String = x.to_string().chars().rev().collect::<String>();
if reversed.chars().last() == Some('-') {
reversed.pop();
}
reversed.parse::<i32>().unwrap()
}
working version: playground
This other post has good explanation of why. In the context of this question:
x.to_string().chars().rev();
// ^ ^
// String <- &str
to_string returns a String, but the code has no reference to that String after this statement, so it needs to free the String, but the iterator refers to the &str from chars() which then becomes a reference to something that no longer exists. By changing the type of reversed to String and using collect then Rust can bind the new data to the local variable and doesn't have to drop it at the end of the statement.
Does the LeetCode challenge impose the int→string→int conversions? I would do it directly on ints:
fn reverse (x: i32) -> i32 {
let mut x = x.abs();
let mut y = 0;
while x != 0 {
y = y*10 + x%10;
x = x/10;
}
return y;
}
Why not just take the absolute value of x before converting it to a String so you don't have to deal with the hyphen edge case?
fn reverse(x: i32) -> i32 {
x.abs()
.to_string()
.chars()
.rev()
.collect::<String>()
.parse::<i32>()
.unwrap()
}
fn main() {
assert_eq!(reverse(1234567), 7654321);
assert_eq!(reverse(-1234567), 7654321);
}
playground
Even if we get the input as a String and have to deal with the hyphen the most idiomatic solution would be to filter() it out:
fn reverse(x: String) -> i32 {
x.chars()
.filter(|&c| c != '-')
.rev()
.collect::<String>()
.parse::<i32>()
.unwrap()
}
fn main() {
assert_eq!(reverse(1234567.to_string()), 7654321);
assert_eq!(reverse((-1234567).to_string()), 7654321);
}
playground
I often use integer type without type annotation:
let mut counter = 0
If there is no constraint, rustc will infer x is a i32. (rfcs/0212-restore-int-fallback.md at master · rust-lang/rfcs).
Sometimes it causes a problem: overflowing.
for _ in 0..1_000_000_000_000usize {
counter += 1; # overflow!
...
}
So I want to tell rustc to deny integer variable without explicit type annotation:
let mut counter = 0; # Deny
let mut counter: u64 = 0; # OK, because `counter` is explicitly annotated with `u64`
How to do this?
There is a new lint default_numeric_fallback:
#[warn(clippy::default_numeric_fallback)]
pub fn is_yelled(s: &str) -> bool {
let (n_upper, n_lower) = s.chars().fold((0, 0), |(n_upper, n_lower), c| {
if c.is_uppercase() {
(n_upper + 1, n_lower)
} else if c.is_lowercase() {
(n_upper, n_lower + 1)
} else {
(n_upper, n_lower)
}
});
n_upper > n_lower
}
will output:
warning: default numeric fallback might occur
--> src/lib.rs:4:46
|
4 | let (n_upper, n_lower) = s.chars().fold((0, 0), |(n_upper, n_lower), c| {
| ^ help: consider adding suffix: `0_i32`
|
note: the lint level is defined here
--> src/lib.rs:1:8
|
1 | #[warn(clippy::default_numeric_fallback)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#default_numeric_fallback
warning: default numeric fallback might occur
--> src/lib.rs:4:49
|
4 | let (n_upper, n_lower) = s.chars().fold((0, 0), |(n_upper, n_lower), c| {
| ^ help: consider adding suffix: `0_i32`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#default_numeric_fallback
warning: default numeric fallback might occur
--> src/lib.rs:6:24
|
6 | (n_upper + 1, n_lower)
| ^ help: consider adding suffix: `1_i32`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#default_numeric_fallback
warning: default numeric fallback might occur
--> src/lib.rs:8:33
|
8 | (n_upper, n_lower + 1)
| ^ help: consider adding suffix: `1_i32`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#default_numeric_fallback
Unfortunately the lint is not warn for now but only in pedantic list. And it's strange to suggest i32 as default. For example, this code sample should use usize.
Source: https://github.com/rust-lang/rust-clippy/issues/6064
This program dies because of infinite recursion:
use std::any::Any;
trait Foo {
fn get(&self, index: usize) -> Option<&Any>;
}
impl Foo for Vec<i32> {
fn get(&self, index: usize) -> Option<&Any> {
Vec::get(self, index).map(|v| v as &Any)
}
}
fn main() {
let v: Vec<i32> = vec![1, 2, 4];
println!("Results: {:?}", v.get(0))
}
The compiler itself warns about this:
warning: function cannot return without recurring
--> src/main.rs:8:5
|
8 | fn get(&self, index: usize) -> Option<&Any> {
| _____^ starting here...
9 | | Vec::get(self, index).map(|v| v as &Any)
10 | | }
| |_____^ ...ending here
|
= note: #[warn(unconditional_recursion)] on by default
note: recursive call site
--> src/main.rs:9:9
|
9 | Vec::get(self, index).map(|v| v as &Any)
| ^^^^^^^^^^^^^^^^^^^^^
= help: a `loop` may express intention better if this is on purpose
Why does universal call syntax not work in this case? The compiler does not understand that I want to call Vec::get not Foo::get.
How can I fix this, if I do not want to change function names?
To specify which method to call, whether inherent or provided from a trait, you want to use the fully qualified syntax:
Type::function(maybe_self, needed_arguments, more_arguments)
Trait::function(maybe_self, needed_arguments, more_arguments)
Your case doesn't work because Vec doesn't have a method called get! get is provided from the Deref implementation to [T].
The easiest fix is to call as_slice directly:
self.as_slice().get(index).map(|v| v as &Any)
You could also use the fully qualified syntax which requires the angle brackets in this case (<...>) to avoid ambiguity with declaring an array literal:
<[i32]>::get(self, index).map(|v| v as &Any)
universal call syntax
Note that while Rust originally used the term universal function call syntax (UFCS), the usage of this term conflicted with the existing understood programming term, so the use of it is not suggested. The replacement term is fully qualified syntax.
This program dies because of infinite recursion:
use std::any::Any;
trait Foo {
fn get(&self, index: usize) -> Option<&Any>;
}
impl Foo for Vec<i32> {
fn get(&self, index: usize) -> Option<&Any> {
Vec::get(self, index).map(|v| v as &Any)
}
}
fn main() {
let v: Vec<i32> = vec![1, 2, 4];
println!("Results: {:?}", v.get(0))
}
The compiler itself warns about this:
warning: function cannot return without recurring
--> src/main.rs:8:5
|
8 | fn get(&self, index: usize) -> Option<&Any> {
| _____^ starting here...
9 | | Vec::get(self, index).map(|v| v as &Any)
10 | | }
| |_____^ ...ending here
|
= note: #[warn(unconditional_recursion)] on by default
note: recursive call site
--> src/main.rs:9:9
|
9 | Vec::get(self, index).map(|v| v as &Any)
| ^^^^^^^^^^^^^^^^^^^^^
= help: a `loop` may express intention better if this is on purpose
Why does universal call syntax not work in this case? The compiler does not understand that I want to call Vec::get not Foo::get.
How can I fix this, if I do not want to change function names?
To specify which method to call, whether inherent or provided from a trait, you want to use the fully qualified syntax:
Type::function(maybe_self, needed_arguments, more_arguments)
Trait::function(maybe_self, needed_arguments, more_arguments)
Your case doesn't work because Vec doesn't have a method called get! get is provided from the Deref implementation to [T].
The easiest fix is to call as_slice directly:
self.as_slice().get(index).map(|v| v as &Any)
You could also use the fully qualified syntax which requires the angle brackets in this case (<...>) to avoid ambiguity with declaring an array literal:
<[i32]>::get(self, index).map(|v| v as &Any)
universal call syntax
Note that while Rust originally used the term universal function call syntax (UFCS), the usage of this term conflicted with the existing understood programming term, so the use of it is not suggested. The replacement term is fully qualified syntax.