Attributes
Attributes attach metadata or behavior to declarations.
Struct tags
Section titled “Struct tags”#[json]
Section titled “#[json]”Add #[json] to a struct to generate Go JSON struct tags for all fields:
#[json]struct User { name: string, age: int, active: bool,}Generated Go:
type User struct { Name string `json:"name"` Age int `json:"age"` Active bool `json:"active"`}Serialization attributes accept options:
| Option | Effect |
|---|---|
omitempty | Omit field if empty |
!omitempty | Include field if empty |
skip | Exclude field |
snake_case | Convert field name to snake_case |
camel_case | Convert field name to camelCase |
string | Encode numbers as strings |
#[json]struct Config { #[json(omitempty)] timeout: Option<int>,omitted if None
#[json(skip)] internal_id: int,never serialized
#[json(string)] large_number: int64,encoded as "1234", not 1234}Struct-level options apply to all fields. A field-level option overrides them, and an explicit name overrides both:
#[json(snake_case)]struct UserProfile { userName: string,"user_name" from snake_case
createdAt: int,"created_at" from snake_case
#[json("userID")] id: int,"userID", snake_case overridden}Other serializers
Section titled “Other serializers”More supported attributes:
#[xml]#[yaml]#[toml]#[db]#[bson]#[mapstructure]#[msgpack]Attributes stack:
#[json]#[db]struct User { #[json("userName")] #[db("user_name")] name: string,}#[tag]
Section titled “#[tag]”For custom tags, use #[tag]:
#[json]struct Input { #[tag("validate", "required")] email: string,}Generated Go:
type Input struct { Email string `json:"email" validate:"required"`}For more complex tags, use a backticked string:
#[json]struct User { #[tag(`validate:"required,email" gorm:"unique"`)] email: string,}Generated Go:
type User struct { Email string `json:"email" validate:"required,email" gorm:"unique"`}Generated code
Section titled “Generated code”#[iterate]
Section titled “#[iterate]”Add #[iterate] to an enum to synthesize a variants() associated function returning every variant, in declaration order:
#[iterate]enum Direction { North, East, West, South,}
for direction in Direction.variants() { fmt.Println(direction)prints North, East, West, South}#[iterate] works only on enums whose variants carry no data.
#[display]
Section titled “#[display]”By default a struct or enum has no display form. Printing one falls back to Go’s %v, and interpolating one in an f-string is rejected.
struct Point { x: int, y: int,}
let p = Point { x: 1, y: 2 }
fmt.Println(p)prints {1 2}fmt.Println(f"at {p}")error: Point has no display formAdd #[display] to render it as a readable string instead.
#[display]struct Point { x: int, y: int,}
let p = Point { x: 1, y: 2 }
fmt.Println(p)prints Point { x: 1, y: 2 }#[display] also gives the enum or struct a to_string() method.
interface Display { fn to_string() -> string}
fn render(value: Display) -> string { value.to_string()}
render(Point { x: 1, y: 2 })Point satisfies Display#[equality]
Section titled “#[equality]”== and != work on natively comparable types: primitives, arrays whose elements are comparable, and structs, enums, and tuples whose components are all comparable.
struct User { name: string, age: int,}
let u1 = User { name: "Alice", age: 30 }let u2 = User { name: "Alice", age: 30 }
u1 == u2trueOther types are not natively comparable: slices, maps, functions, interfaces, and any array, struct, enum, or tuple that contains a non-comparable value.
struct Order { id: int, tags: Slice<string>,not natively comparable}
let o1 = Order { id: 1, tags: ["a"] }let o2 = Order { id: 1, tags: ["a"] }
o1 == o2error: Order cannot be compared with ==For maps and slices, use the built-in equals() method:
let a = [1, 2, 3]let b = [1, 2, 3]
a.equals(b)trueTo enable comparison on types that are not natively comparable and do not have a built-in equals() method, mark them with the #[equality] attribute. This will auto-generate an equals() method to compare the type structurally.
#[equality]struct Order { id: int, tags: Slice<string>,}
let a = Order { id: 1, tags: ["a"] }let b = Order { id: 1, tags: ["a"] }
a.equals(b)trueThe auto-generated equals() method compares by these rules:
==for comparable fields.equals()for slice and map fields- the field type’s own
equalsfor nested#[equality]types
If you need a custom comparator, write an equals method yourself:
struct Fraction { numerator: int, denominator: int,}
impl Fraction { fn equals(self, other: Fraction) -> bool { self.numerator * other.denominator == other.numerator * self.denominator }}
let a = Fraction { numerator: 1, denominator: 2 }let b = Fraction { numerator: 2, denominator: 4 }
a.equals(b)true#[equality] works on generic structs and enums, as long as the type parameter is bound by Comparable or Ordered.
#[equality]struct Cart<T: Comparable> { items: Slice<T>}
let a = Cart { items: [1, 2, 3] }let b = Cart { items: [1, 2, 3] }
a.equals(b)trueThe bound can also be a custom interface instead, as long as the interface declares an equals method.
interface Equatable<T> { fn equals(other: T) -> bool}
#[equality]struct Batch<T: Equatable<T>> { item: T}
let a = Batch { item: Order { id: 1, tags: ["a"] } }let b = Batch { item: Order { id: 1, tags: ["a"] } }
a.equals(b)true#[allow]
Section titled “#[allow]”#[allow(lint)] on a function silences that lint.
For most lints, place the attribute on the function whose code is flagged:
#[allow(match_on_bool)]silences the lint for this functionfn describe(ready: bool) -> string { match ready { true => "go", false => "wait", }}For unused-value lints (unused_result, unused_option, unused_literal, unused_value), place #[allow] on the function whose result is ignored, so every call to it stops warning.
import "go:os"
#[allow(unused_result)]silences the lint at every call belowfn warm_cache(path: string) -> Result<Slice<byte>, error> { os.ReadFile(path)}
fn main() { warm_cache("/config") warm_cache("/data")}For the unused-item lints (unused_function, unused_type, unused_struct_field, unused_enum_variant), place #[allow] on the flagged declaration itself. An allow on a struct or enum also covers its fields and variants.
#[allow(unused_enum_variant)]enum Direction { North, South,}
fn main() { let _ = Direction.North}