Iterate over struct in rust
Asked Answered
J

2

6

I am completely new to Rust coming from JS/TS

I have already seen other questions like: How do I iterate over elements of a struct in Rust? but they didn't get me to a real answer.

I am trying to iterate over the keys and values of a struct in rust

In JS/TS this would work like this:

const o = {
    a: "hello",
    b: "world"
};

const keys = Object.keys(o);
const values = Object.values(o);

// now loop over them 

How would something like this work in Rust?

I am using Serde to parse a config yaml file to a struct.


#[derive(Deserialize, Debug, Clone)]
pub struct Config {
    pub headers: Headers,
}

#[derive(Deserialize, Debug, Clone)]
pub struct Headers {
    #[serde(rename = "Content-Security-Policy")]
    pub content_security_policy: String,
    #[serde(rename = "x-frame-options")]
    pub x_frame_options: String,
    #[serde(rename = "x-content-type-options")]
    pub x_content_type_options: String,
    #[serde(rename = "x-permitted-cross-domain-policies")]
    pub x_permitted_cross_domain_policies: String,
    #[serde(rename = "x-download-options")]
    pub x_download_options: String,
    #[serde(rename = "x-xss-protection")]
    pub x_xss_protection: String,
    #[serde(rename = "referrer-policy")]
    pub referrer_policy: String,
    #[serde(rename = "Strict-Transport-Security")]
    pub strict_transport_security: String,
    #[serde(rename = "feature-policy")]
    pub feature_policy: String,
    #[serde(rename = "Cache-Control")]
    pub cache_control: String,
}

But this does not implement the .iter() function and i haven't found a solution searching for this.

Jerrine answered 30/3, 2022 at 11:31 Comment(4)
Does this answer your question? How do I iterate over elements of a struct in Rust?Attract
No this just leads down to another question that is even further away from an answerJerrine
You cant iterate over structs in rust. But since you're already using serde, you could use that to convert your struct to something that can be iterated, e.g. a HashMap<String, String>. See here.Ransdell
It says pretty explicitly: "No. You have to implement it yourself, or find a macro / compiler plugin that will do it for you.".Attract
J
6

Thanks to Caesar

I tried this:


use serde::{Deserialize, Serialize};

#[derive(Deserialize, Debug, Clone, Serialize)]
pub struct Config {
    pub headers: Headers,
}

#[derive(Deserialize, Debug, Clone, Serialize)]
pub struct Headers {
    #[serde(rename = "Content-Security-Policy")]
    pub content_security_policy: String,
    #[serde(rename = "x-frame-options")]
    pub x_frame_options: String,
    #[serde(rename = "x-content-type-options")]
    pub x_content_type_options: String,
    #[serde(rename = "x-permitted-cross-domain-policies")]
    pub x_permitted_cross_domain_policies: String,
    #[serde(rename = "x-download-options")]
    pub x_download_options: String,
    #[serde(rename = "x-xss-protection")]
    pub x_xss_protection: String,
    #[serde(rename = "referrer-policy")]
    pub referrer_policy: String,
    #[serde(rename = "Strict-Transport-Security")]
    pub strict_transport_security: String,
    #[serde(rename = "feature-policy")]
    pub feature_policy: String,
    #[serde(rename = "Cache-Control")]
    pub cache_control: String,
}

let iterable_headers: HashMap<String, String> =
 serde_yaml::from_value(serde_yaml::to_value(&config.headers).unwrap()).unwrap();

for header in &iterable_headers {
    res = res.header(header.0, header.1);
}

Jerrine answered 30/3, 2022 at 11:49 Comment(0)
M
7

You can use struct_iterable crate.

use struct_iterable::Iterable;
            
#[derive(Iterable)]
struct MyStruct {
    field1: u32,
    field2: String,
    field3: Option<String>,
    // etc.
}
    
let my_instance = MyStruct {
    field1: 42,
    field2: "Hello, world!".to_string(),
    field3: Some("Hello, world!".to_string()),
};
    
for (field_name, field_value) in my_instance.iter() {
    if let Some(string_opt) = field_value.downcast_ref::<Option<String>>() {
        if let Some(string) = string_opt.as_deref() {
            println!("{} optional String: {:?}", field_name, field_value);
        }
    }
    println!("{}: {:?}", field_name, field_value);
}
Molding answered 10/5, 2023 at 19:28 Comment(0)
J
6

Thanks to Caesar

I tried this:


use serde::{Deserialize, Serialize};

#[derive(Deserialize, Debug, Clone, Serialize)]
pub struct Config {
    pub headers: Headers,
}

#[derive(Deserialize, Debug, Clone, Serialize)]
pub struct Headers {
    #[serde(rename = "Content-Security-Policy")]
    pub content_security_policy: String,
    #[serde(rename = "x-frame-options")]
    pub x_frame_options: String,
    #[serde(rename = "x-content-type-options")]
    pub x_content_type_options: String,
    #[serde(rename = "x-permitted-cross-domain-policies")]
    pub x_permitted_cross_domain_policies: String,
    #[serde(rename = "x-download-options")]
    pub x_download_options: String,
    #[serde(rename = "x-xss-protection")]
    pub x_xss_protection: String,
    #[serde(rename = "referrer-policy")]
    pub referrer_policy: String,
    #[serde(rename = "Strict-Transport-Security")]
    pub strict_transport_security: String,
    #[serde(rename = "feature-policy")]
    pub feature_policy: String,
    #[serde(rename = "Cache-Control")]
    pub cache_control: String,
}

let iterable_headers: HashMap<String, String> =
 serde_yaml::from_value(serde_yaml::to_value(&config.headers).unwrap()).unwrap();

for header in &iterable_headers {
    res = res.header(header.0, header.1);
}

Jerrine answered 30/3, 2022 at 11:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.