Why can't print a struct field with formatted print? - rust

Like following code,
it does working to print values with formatted print, when values are primitive values or struct(with derive debug attribute), or something.
But I can't print values when values are struct fields.
#[derive(Debug)]
struct Point<T> {
x: T,
y: T,
}
fn main() {
let a = 3;
let p = Point { x: 5, y: 10 };
println!("{}", a); // Working
println!("{a}"); // Working
println!("{:?}", p); // Working
println!("{p:?}"); // Working
println!("{} {}", p.x, p.y); // Working
println!("{p.x} {p.y}"); // Not working
}
The error message is following.
error: invalid format string: expected `'}'`, found `'.'`
--> src/main.rs:18:17
|
18 | println!("{p.x} {p.y}"); // Not working
| - ^ expected `}` in format string
| |
| because of this opening brace
|
= note: if you intended to print `{`, you can escape it using `{{`
error: could not compile `rust-ex` due to previous error
I think that the type of p.x and p.y is i32 so they can printed with formatted print but it doesn't.
Is there any way to print struct fields with formatter print? Or is there anything need to implement?

Your problem is not a formatting problem, just an issue with what exactly println! accepts in its formatting string.
Contrary to what you may experience in other languages, the part between braces in the literal string in a println! is not a string escape, meaning that you could put any (printable) Rust expression. Instead, you should see it as a named parameter. Therefore, it can only be a variable name. println! also allows you to mimic variable definition if you don't already have a variable with that name, like this:
println!("{px}", px = p.x);

Another similar but different issue is trying to println! when you have a Rust variable that is an underscore:
let _ = 2;
println!("Value of _ is {_}");
The error is:
invalid format string: invalid argument name `_`
...
println!("Value of _ is {_}");
^ invalid argument name in format string
This is probably because the underscore is meant to be ignored
The underscore (_) is a reserved identifier in Rust and serves different purposes depending on the context. It usually means that something is ignored.
Other sites explain how in rust, the underscore does "not bind to the variable"; or "does not have ownership of the object"
See #jthulhu's comment --not only is _ meant to be ignored in Rust, the _ variable cannot be used in Rust; therefore isn't even allocated (that explains my error messages). This is different from other programming languages, where the _ variable is just a convention to signify the _ variable is meant to be ignored but could be used. In Rust, as #jthulhu says: "Basically, doing let _ = 3; will result in absolutely nothing even without optimizations"
I know the OP already found the best accepted answer. I just want to offer this answer in case other folks search for "invalid format string" or "invalid argument name _" and find this SO question.
If you tried a workaround like:
println!("Value of _ is {}", _);
Then you get a new error, reinforcing the idea that the underscore variable is never meant to be used:
in expressions, `_` can only be used on the left-hand side of an assignment
`_` not allowed here
So the underscore variable is allowed on the left-hand side of an assignment as in my code above, or this underscore expression where the _ signifies a placeholder in a destructuring assignment, but you can't reference the underscore variable later, including in println!. The only solution is to use a different variable name.

Related

What does the Some(..) syntax mean?

I wrote this snippet:
let my_option: Option<()> = None;
if my_option.is_some() {
my_option.unwrap();
}
Clippy is telling me to use:
if let Some(..) = my_option {
my_option.unwrap();
}
What does Some(..) mean? Is it just dropping the value similar to how using _ would in some cases? And where can I find more information about when and where I can use the ..?
I think the Clippy warning is slightly misleading. Let's first look at the full warning message:
warning: called `unwrap` on `my_option` after checking its variant with `is_some`
--> src/main.rs:4:9
|
3 | if my_option.is_some() {
| ---------------------- help: try: `if let Some(..) = my_option`
4 | my_option.unwrap();
| ^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(clippy::unnecessary_unwrap)]` on by default
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap
Clippy is complaining about the use of unwrap() after checking with is_some(). If you use is_some() only or unwrap() only, Clippy won't complain. It's only unwrapping after checking that's considered unidiomatic, since it can be easier done using if let.
I believe the reason for Clippy to suggest if let Some(..) = my_option is that the code does not track how the inner value is used later, so the suggestion needs to be somehow generic. In practice, you would hardly ever literally write .. here, but instead write something like
if let Some(value) = my_option
to bind the inner value to a variable. Also note that if let Some(..) = my_option does not consume the option, while if let Some(value) = my_option does (if the inner type is not Copy).
In summary:
If you want to check whether an option is Some, but are not interested in the contained value, you should use if my_option.is_some().
If you are certain at compile time that your option must be Some, and you want to extract the inner value, use my_option.unwrap() without any enclosing if.
If you don't know whether the option is Some, and you want to extract the inner value only in case it is, use if let Some(value) = my_value.
Completing the excellent answer by #SvenMarnach, .. does have a meaning in patterns and it's indeed very similar to _: while _ means "ignore one field here", .. means "ignore zero or more fields here".
As such, in almost any place you can use _ you can also use .., although it can lead to mistakes if fields are added later. The only exceptions are identifier patterns - you can do if let _ = 123 but not if let .. = 123, and struct patterns because it has special syntax: ignoring one field is Struct { field: _ }, while ignoring many is Struct { .. }.

When defining a new variable, how to decide its type according to the string value of a constant (or other variable)?

I want to be able to decide the type of a new variable by the name of a previous variable, for example:
//the text of this variable must determine the type of the second variable
const TYPE_NAME: &str = "u16";
fn main() {
//if this worked, this second_variable must be of type u16, which is the string text indicated in type_name
let second_variable: {TYPE_NAME} = 777;
println!("TYPE_NAME: {}, second_variable: {}", TYPE_NAME, second_variable);
}
However this code is incorrect, and I get this error:
error[E0573]: expected type, found constant `TYPE_NAME`
--> test.rs:5:23
|
5 | let second_variable: TYPE_NAME = 777;
| ^^^^^^^^^ not a type
error: aborting due to previous error
For more information about this error, try `rustc --explain E0573`.
How can I do this? Is there some other way to do it besides a match loop?
The detail is that this must be used in multiple parts of the code, and will ideally be defined with a constant, so, for example, I can in one line change the maximum value of my numeric variables from u16 to u32 or turn them into floats f64, or something like that.
You cannot declare a type from a string, but what you want is a type alias:
type Type = u16;
let second_variable: Type = 777;

Formatting a const string in Rust [duplicate]

This extremely simple Rust program:
fn main() {
let c = "hello";
println!(c);
}
throws the following compile-time error:
error: expected a literal
--> src/main.rs:3:14
|
3 | println!(c);
| ^
In previous versions of Rust, the error said:
error: format argument must be a string literal.
println!(c);
^
Replacing the program with:
fn main() {
println!("Hello");
}
Works fine.
The meaning of this error isn't clear to me and a Google search hasn't really shed light on it. Why does passing c to the println! macro cause a compile time error? This seems like quite unusual behaviour.
This should work:
fn main() {
let c = "hello";
println!("{}", c);
}
The string "{}" is a template where {} will be replaced by the next argument passed to println!.
TL;DR If you don't care why and just want to fix it, see the sibling answer.
The reason that
fn main() {
let c = "hello";
println!(c);
}
Cannot work is because the println! macro looks at the string at compile time and verifies that the arguments and argument specifiers match in amount and type (this is a very good thing!). At this point in time, during macro evaluation, it's not possible to tell that c came from a literal or a function or what have you.
Here's an example of what the macro expands out to:
let c = "hello";
match (&c,) {
(__arg0,) => {
#[inline]
#[allow(dead_code)]
static __STATIC_FMTSTR: &'static [&'static str] = &[""];
::std::io::stdio::println_args(&::std::fmt::Arguments::new(
__STATIC_FMTSTR,
&[::std::fmt::argument(::std::fmt::Show::fmt, __arg0)]
))
}
};
I don't think that it's actually impossible for the compiler to figure this out, but it would probably take a lot of work with potentially little gain. Macros operate on portions of the AST and the AST only has type information. To work in this case, the AST would have to include the source of the identifier and enough information to determine it's acceptable to be used as a format string. In addition, it might interact poorly with type inference - you'd want to know the type before it's been picked yet!
The error message asks for a "string literal". What does the word "literal" mean? asks about what that means, which links to the Wikipedia entry:
a literal is a notation for representing a fixed value in source code
"foo" is a string literal, 8 is a numeric literal. let s = "foo" is a statement that assigns the value of a string literal to an identifier (variable). println!(s) is a statement that provides an identifier to the macro.
If you really want to define the first argument of println! in one place, I found a way to do it. You can use a macro:
macro_rules! hello {() => ("hello")};
println!(hello!());
Doesn't look too useful here, but I wanted to use the same formatting in a few places, and in this case the method was very helpful:
macro_rules! cell_format {() => ("{:<10}")}; // Pads with spaces on right
// to fill up 10 characters
println!(cell_format!(), "Foo");
println!(cell_format!(), 456);
The macro saved me from having to duplicate the formatting option in my code.
You could also, obviously, make the macro more fancy and take arguments if necessary to print different things with different arguments.
If your format string will be reused only a moderate number of times, and only some variable data will be changed, then a small function may be a better option than a macro:
fn pr(x: &str) {
println!("Some stuff that will always repeat, something variable: {}", x);
}
pr("I am the variable data");
Outputs
Some stuff that will always repeat, something variable: I am the variable data

How do I create an iterator of lines from a file that have been split into pieces?

I have a file that I need to read line-by-line and break into two sentences separated by a "=". I am trying to use iterators, but I can't find how to use it properly within split. The documentation says that std::str::Split implements the trait, but I'm still clueless how to use it.
use std::{
fs::File,
io::{prelude::*, BufReader},
};
fn example(path: &str) {
for line in BufReader::new(File::open(path).expect("Failed at opening file.")).lines() {
let words = line.unwrap().split("="); //need to make this an iterable
}
}
How can I use a trait I know is already implemented into something like split?
As #Mateen commented, split already returns an iterable. To fix the lifetime problems, save the value returned by unwrap() into a variable before calling split.
I'll try to explain the lifetime issue here.
First it really helps to look at the function signatures.
pub fn unwrap(self) -> T
pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P>
unwrap is pretty simple, it takes ownership of itself and returns the inner value.
split looks scary, but it's not too difficult, 'a is just a name for the lifetime, and it just states how long the return value can be used for. In this case it means that both the input arguments must live at least as long as the return value.
// Takes by reference, no ownership change
// v
pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P>
// ^ ^ ^ ^
// | |--|---| |
// This just declares a name. | |
// | |
// Both of these values must last longer than -----|
This is because split doesn't copy any of the string, it just points to the position on the original string where the split takes place. If the original string for some reason was dropped, the Split will not point to invalid data.
A variable's lifetime (unless the ownership is passed to something else) lasts till it is out of scope, this is either at the closing } if it is named (e.g. with let) or it is at the end of line / ;
That's why there is a lifetime problem in your code:
for line in std::io::BufReader::new(std::fs::File::open(path).expect("Failed at opening file.")).lines() {
let words = line
.unwrap() // <--- Unwrap consumes `line`, `line` can not be used after calling unwrap(),
.split("=") // Passed unwrap()'s output to split as a reference
; //<-- end of line, unwrap()'s output is dropped due to it not being saved to a variable, the result of split now points to nothing, so the compiler complains.
}
Solutions
Saving the return value of unwrap()
for line in std::io::BufReader::new(std::fs::File::open("abc").expect("Failed at opening file.")).lines() {
let words = line.unwrap();
let words_split = words.split("=");
} // <--- `word`'s lifetime ends here, but there is no lifetime issues since `words_split` also ends here.
You can rename words_split to words to shadow the original variable to not clutter variable names if you want, this also doesn't cause an issue since shadowed variables are not dropped immediately, but at the end of its original scope.
Or
Rather than having a iterator of type str, all of which are just fancy pointers to the original string, you can copy each slice out to it's own string, removing the reliance on keeping the original string in scope.
There is almost certainly no reason to do this in your case, since copying each slice takes more processing power and more memory, but rust gives you this control.
let words = line
.unwrap()
.split("=")
.map(|piece|
piece.to_owned() // <--- This copies all the characters in the str into it's own String.
).collect::<Vec<String>>()
; // <--- unwrap()'s output dropped here, but it doesn't matter since the pieces no longer points to the original line string.
let words_iterator = words.iter();
collect gives you the error cannot infer type because you didn't state what you wanted to collect into, either use the turbofish syntax above, or state it on words i.e. let words: Vec<String> = ...
You have to call collect because map doesn't do anything unless you use it, but that's out of the scope of this answer.

How to concatenate a literal string with a const string?

I am trying to instantiate an argument parser (clap).
There is code like:
const DEFAULT_VALUE: &'static str = "12312312";
// ...
.help("this parameter is for (default:" + DEFAULT_VALUE + ")")
// ...
I looked through similar existing questions and discovered concat! macro and lazy_static.
First option doesn't fit and there is no example for lazy_static.
If it's possible it's will be over complicated anyway because lazy_static requires to define a block in a separate place.
I am looking some concise syntax sugar with a macro in place, without a lot of type overhead.
If define a local variable it could get to high because DSL for clap could be very long. It's not convenient, because it rips the string from its logical place in code.
Another approach to define static variable for the whole help string but it posses the same drawback as the approach above plus namespace pollution.
Suggested solution with format! doesn't fit too. It requires to define a local variable.
Example
extern crate clap;
use clap::{Arg, App};
const DEFAULT: &'static str = "1";
fn main() {
let params = App::new("app")
.arg(Arg::with_name("p")
// here 100 lines of the uninterruptable expression
.help(&format!("parameter p (DEFAULT: {})", DEFAULT)))
// here also 100 lines of the uninterruptable expression
.get_matches();
println!("param p = {}", params.value_of("p").unwrap())
}
Cargo.toml
[package]
name = "demo-clap"
version = "1.0.0"
[dependencies]
clap = "2.10.0"
Compilation error
<std macros>:2:1: 2:61 error: borrowed value does not live long enough
<std macros>:2 $ crate :: fmt :: format ( format_args ! ( $ ( $ arg ) * ) ) )
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/main.rs:11:21: 11:66 note: in this expansion of format! (defined in <std macros>)
src/main.rs:13:24: 15:2 note: reference must be valid for the block suffix following statement 0 at 13:23...
src/main.rs:13 .get_matches();
^
src/main.rs:8:5: 13:24 note: ...but borrowed value is only valid for the statement at 8:4
src/main.rs:8 let params = App::new("app")
^
src/main.rs:8:5: 13:24 help: consider using a `let` binding to increase its lifetime
src/main.rs:8 let params = App::new("app")
^
error: aborting due to previous error
error: Could not compile `demo-clap`.
If you're working with Rust 1.46.01 or later, check out the const_format crate on (crates.io | docs.rs).
concatcp: Concatenates integers2, bool, and &str constants into &'static str.
formatcp: format-like formatting (emits a &'static str); takes the same primitives as concatcp
So for your example, formatcp would provide the most flexible solution and does not require the local variable you mention (I'm assuming you're referring to the heap-allocated String resulting from alloc::fmt::format in the format! macro):
use clap::{Arg, App};
use const_format::formatcp;
const DEFAULT: &'static str = "1";
fn main() {
let params = App::new("app")
.arg(Arg::with_name("p")
.help(formatcp!("parameter p (DEFAULT: {})", DEFAULT)))
.get_matches();
println!("param p = {}", params.value_of("p").unwrap())
}
Running with app -h gives
app
USAGE:
app [p]
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
ARGS:
<p> parameter p (DEFAULT: 1)
Limitations of all macros in the crate:
Macros that expand to &'static str (i.e. the ones I mentioned) only accept constants from concrete types:
Type::<u8>::FOO OK ✅
Type::<TYPE_PARAMETER>::FOO BAD ❌
Integer arguments need to be constrained (i.e. must add i*/u* suffix when using literals).
Can't be used in some places that take string literals only, namely attributes which can require LiteralExpression.
#[doc = "ab"] != #[doc = concatcp!("a", "b")]
1 This is needed for the stabilized const fn improvements, which allow for looping without "heinous hackery" involving std::mem::transmute
2 More specifically, this would be all the i*/u* primitives. Note that if you'll have to constrain the type yourself by using the suffix desired if you're passing in literals.
You can simply use a reference and the format! macro:
.help(&format!("this parameter is for (default: {})", DEFAULT_VALUE));
Edit:
What you want to do is not possible in Rust:
This is a fundamental limitation of macros in that they are working
with nothing more than various tokens. They have no understanding of
types, just tokens that look like types. When concat! sees DESCRIPTION
it just sees an identifier, it has no idea that it is a string
constant. What could work here though is some sort of string
concatenation const fn as that could take the values of constants to
create new constants, although that would require some dark magic.
You could do this instead:
macro_rules! DEFAULT {
() => { "1" };
}
fn main() {
let params = App::new("app")
.arg(Arg::with_name("p")
// here 100 lines of the uninterruptable expression
.help(concat!("parameter p (DEFAULT: ", DEFAULT!(), ")")))
// here also 100 lines of the uninterruptable expression
.get_matches();
println!("param p = {}", params.value_of("p").unwrap())
}
The use of a macro instead of a constant allows you to use the concat! macro.

Resources