본문으로 건너뛰기

Serde

Enum Tags

In Serde, a tag is discriminator data that identifies which enum variant a serialized value represents.

The default enum representation is externally tagged:

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
enum Event {
Login { user: String },
Logout { user: String },
}
{ "Login": { "user": "alice" } }

Use #[serde(tag = "...")] when the serialized format should carry the variant name in a field:

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type")]
enum Event {
Login { user: String },
Logout { user: String },
}
{ "type": "Login", "user": "alice" }

Here, type is the tag field and Login is the variant value.

Lower-Case Tags

Use rename_all = "lowercase" on the enum to serialize and deserialize enum variant names as lower-case strings:

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "lowercase")]
enum Event {
Login { user: String },
Logout { user: String },
}
{ "type": "login", "user": "alice" }

For multi-word variant names, lowercase removes word boundaries:

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "lowercase")]
enum Event {
UserLogin { user: String },
}
{ "type": "userlogin", "user": "alice" }

Prefer snake_case when the serialized variant name should preserve word boundaries:

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
enum Event {
UserLogin { user: String },
}
{ "type": "user_login", "user": "alice" }

Use rename for a one-off variant name:

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type")]
enum Event {
#[serde(rename = "login")]
Login { user: String },

#[serde(rename = "logout")]
Logout { user: String },
}

Common Representations

Internally tagged enums place the tag beside the variant fields:

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "lowercase")]
enum Event {
Login { user: String },
}
{ "type": "login", "user": "alice" }

Adjacently tagged enums separate the tag from the variant payload:

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type", content = "data", rename_all = "lowercase")]
enum Event {
Login { user: String },
}
{ "type": "login", "data": { "user": "alice" } }

Untagged enums omit the tag. Serde chooses a variant by matching the input shape, so this is best reserved for compatibility with formats that do not carry a discriminator:

#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
enum Event {
Login { user: String },
Count(u64),
}