How to print structs and arrays? - how does one pretty print a rust struct or any data type?
Sure, one can write the custom Debug method. But is there some way which enables the print by default?
One option is to use: https://docs.rs/pretty-trait/latest/pretty_trait/
When you implement Debug, Rust provides "pretty printing" with {:#?}. From the std::fmt documentation:
# - This flag indicates that the “alternate” form of printing should be used. The alternate forms are:
{:#?} - pretty-print the Debug formatting (adds linebreaks and indentation)
[others omitted]
Example:
#[derive(Debug)]
struct Person {
name: &'static str,
age: u8,
hobbies: Vec<&'static str>,
}
fn main() {
let peter = Person {
name: "Jesse",
age: 49,
hobbies: vec!["crosswords", "sudoku"],
};
println!("{:#?}", peter);
}
Output:
Person {
name: "Jesse",
age: 49,
hobbies: [
"crosswords",
"sudoku",
],
}
Playground
Related
How to print structs and arrays? - how does one pretty print a rust struct or any data type?
Sure, one can write the custom Debug method. But is there some way which enables the print by default?
One option is to use: https://docs.rs/pretty-trait/latest/pretty_trait/
When you implement Debug, Rust provides "pretty printing" with {:#?}. From the std::fmt documentation:
# - This flag indicates that the “alternate” form of printing should be used. The alternate forms are:
{:#?} - pretty-print the Debug formatting (adds linebreaks and indentation)
[others omitted]
Example:
#[derive(Debug)]
struct Person {
name: &'static str,
age: u8,
hobbies: Vec<&'static str>,
}
fn main() {
let peter = Person {
name: "Jesse",
age: 49,
hobbies: vec!["crosswords", "sudoku"],
};
println!("{:#?}", peter);
}
Output:
Person {
name: "Jesse",
age: 49,
hobbies: [
"crosswords",
"sudoku",
],
}
Playground
I need to write a bunch of struct with similar name within it. Such as:
pub struct ContactUpdate {
pub full_name: String,
pub full_address: String,
/// .... many other fields
}
pub struct Contact {
pub contact_id: Option<ObjectId>,
pub full_name: String,
pub full_address: String,
pub created_at: DateTime
/// .... many other fields
}
/// ... other structs with similar content/field name
I'm lazy. So instead of hard-coding each field name by hand, I think how can I make the field name of the struct into contants with fewer characters so I don't have to type as much. Also with other benefits to export that constants and use it in other files that need it.
pub const ID: &str = "contact_id";
pub const NAME: &str = "full_name";
pub const TIME: &str = "created_at";
pub const ADDR: &str = "full_address";
pub struct Contact {
pub ID: Option<ObjectId>,
pub NAME: String,
pub ADDR: String,
pub TIME: DateTime
/// .... many other fields
}
pub struct ContactUpdate {
pub NAME: String,
pub ADDR: String,
/// .... many other fields
}
Is this possible?
No. It is impossible.
If you really want (don't!) you can have a macro for that.
However, the entire reason for the existence of field names is for the programmers to know what they mean. If you want to use them as constants, you just give them no meaning and can get rid of them completely. At that time, you're back to the old days where variable name lengths were limited to 7-8 characters and people used all sorts of bad and unreadable codes to work with that. Don't do that.
In Rust 1.58, println!("{x}"); is supported (Captured identifiers in format strings), but I cannot print the struct because I don't specify {:?}. Are there any ways to display struct with the new println!?
#[derive(Debug)]
struct Structure {
name: String,
version: u32
}
fn main() {
let structure = Structure { name: "name".to_string(), version: 1 };
println!("{:?}", structure); // working
println!("{structure}"); // not working
}
You can add the :? debug modifier as part of the formatting as well:
println!("{structure:?}");
Playground
I'd like to read attributes programatically. For example, I have a struct which has attributes attached to each field:
#[derive(Clone, Debug, PartialEq, Message)]
pub struct Person {
#[prost(string, tag="1")]
pub name: String,
/// Unique ID number for this person.
#[prost(int32, tag="2")]
pub id: i32,
#[prost(string, tag="3")]
pub email: String,
#[prost(message, repeated, tag="4")]
pub phones: Vec<person::PhoneNumber>,
}
(source)
I'd like to find the tag associated with the email field.
I expect there is some code like this to get the tag at runtime:
let tag = Person::email::prost::tag;
Since attributes are read only at compile time you need to write a procedural macro to solve such issue.
You can find information with following designators in your macro.
Field name with ident
Attribute contents with meta
After you find your field name and your meta, then you can match the stringified result with given input parameter in macro like following:
macro_rules! my_macro {
(struct $name:ident {
$(#[$field_attribute:meta] $field_name:ident: $field_type:ty,)*
}) => {
struct $name {
$(#[$field_attribute] $field_name: $field_type,)*
}
impl $name {
fn get_field_attribute(field_name_prm : &str) -> &'static str {
let fields = vec![$(stringify!($field_name,$field_attribute)),*];
let mut ret_val = "Field Not Found";
fields.iter().for_each(|field_str| {
let parts : Vec<&str> = field_str.split(' ').collect();
if parts[0] == field_name_prm{
ret_val = parts[2];
}
});
ret_val
}
}
}
}
my_macro! {
struct S {
#[serde(default)]
field1: String,
#[serde(default)]
field2: String,
}
}
Please note that it assumes that every field in the struct has an attribute. And every field declaration is ending with , including last field. But with some modification on regex you can make it available for optional attributes as well.
Here working solution in Playground
For further info about designators here is the reference
Also you can take a quick look for procedural macros here
I want to generate a HashMap which use struct fields as key, and use usize integer as value.
pub struct Article {
title: String,
content: String,
category: String,
comments: Vec<Comment>
}
pub struct Comment {
content: String
}
My expected output is:
{
title: 0,
content: 1,
category: 2
comments[].content: 3
}
My solution is impl my trait FieldsMapping for both Article and Comment:
pub trait FieldsMapping {
fn get_fields_map(&self) -> HashMap<String, usize>;
}
I want to write a compiler plugin for custom derive FieldsMapping.
How I get all fields within compiler plugin? And how can I know that fields type is Vec or other?
You don't.
Compiler plugins (i.e. procedural macros) are expanded before this information exists, so you can't access it. No, you can't delay expansion until types exist. No, if you turn it into a lint, you can't generate code, which then defeats the purpose of having a procedural macro.