This page is for Go developers who want a compact type for data that only matters in one place: tests, JSON envelopes, or a function that returns a small bundle of fields. It explains how anonymous (inline / unnamed) struct literals work, how they compare to named types, how they interact with JSON, and what people mean when they search for an anonymous struct with a method (spoiler: you need a named type or a helper, not a receiver on the literal type). For broader struct topics, see structs in Go; for JSON decoding patterns, see JSON unmarshal in Go and parse JSON in Go. For methods and receivers in general, see methods in Go and methods vs functions.
Tested with Go 1.24 on Linux.
Quick answer: unnamed struct types
An anonymous struct is a struct type declared inline as struct { ... } without a separate type name. People also call it an inline struct or unnamed struct. You use it for one-off shapes; the compiler still checks field names and types exactly like a named struct.
What is an anonymous struct?
A named struct is introduced at package scope, for example type Person struct { Name string }. An anonymous struct spells the same field list next to a value or in a signature: struct { Name string }{Name: "Ada"}. The type exists only where it is written; two anonymous literals with identical fields in different places are still distinct types for assignment purposes unless you unify them with a named type.
Named vs anonymous
| Named struct | Anonymous struct | |
|---|---|---|
| Declaration | type T struct { ... } |
struct { ... }{...} or var v struct{...} |
| Reuse | Same T everywhere |
Repeat literal or switch to type |
| Methods | func (t T) M() or func (t *T) M() at package level |
No stable type name for a receiver |
Syntax: declare, initialize, zero values
The type and value can appear together. Fields follow the usual struct rules (exported names start with an uppercase letter if other packages must see them).
package main
import "fmt"
func main() {
person := struct {
name string
age int
}{
name: "John Doe",
age: 30,
}
fmt.Println(person.name, person.age)
var empty struct{ ID int; OK bool }
fmt.Printf("zero: %#v\n", empty)
}You should see John Doe 30 and a zero struct line with ID:0 and OK:false.
When to use anonymous structs
Good fits: one-off locals, table-driven test tables, small JSON request or response bodies you only decode once, and temporary grouping inside a function. Poor fits: the same field layout copied in many files, large nested APIs, or anything that needs a clear exported contract—in those cases introduce a named type.
Table-driven style without a top-level type
The struct { ... } form is common in tests; the same idea works in main for small tables:
package main
import "fmt"
func main() {
cases := []struct {
name string
n int
want int
}{
{"square of three", 3, 9},
{"square of zero", 0, 0},
}
for _, tc := range cases {
got := tc.n * tc.n
fmt.Println(tc.name, got == tc.want)
}
}You should see two lines ending in true.
JSON and small API shapes
Anonymous structs work with encoding/json tags the same way named types do—useful when you only care about a subset of fields. For larger models, prefer a named type.
package main
import (
"encoding/json"
"fmt"
)
func main() {
in := struct {
ID int `json:"id"`
Name string `json:"name"`
}{1, "John Doe"}
b, err := json.Marshal(in)
if err != nil {
panic(err)
}
fmt.Println(string(b))
var out struct {
ID int `json:"id"`
Name string `json:"name"`
}
if err := json.Unmarshal(b, &out); err != nil {
panic(err)
}
fmt.Println(out.ID, out.Name)
}You should see one JSON object line, then 1 John Doe.
Slices and maps
Element types can be anonymous struct literals as long as every element uses the same shape:
package main
import "fmt"
func main() {
people := []struct {
ID int
Name string
}{
{1, "Alice"},
{2, "Bob"},
}
fmt.Println(len(people), people[0].Name)
m := map[string]struct {
Age int
}{
"ada": {40},
}
fmt.Println(m["ada"].Age)
}You should see 2 Alice then 40.
Return an anonymous struct from a function
You can name the literal struct type in the function signature so callers get a precise shape without a package-level type alias. That is fine for private helpers; for exported APIs, a named type documents intent and stays stable when fields evolve.
package main
import "fmt"
func newPoint(x, y int) struct{ X, Y int } {
return struct{ X, Y int }{X: x, Y: y}
}
func main() {
p := newPoint(3, 4)
fmt.Println(p.X, p.Y)
}You should see 3 4.
Anonymous struct with method (what works and what does not)
Searchers often ask whether a golang anonymous struct can have methods. Method declarations in Go must live at package scope and use a defined receiver type. You cannot attach func (s struct{...}) M() to a one-off anonymous struct literal as if it were its own class inside main.
Practical options:
- A package-level named type if you need real methods and
recv.M()syntax. - A plain function that takes the struct value or pointer and performs the operation.
- Embedding a named type that already has methods so those methods promote onto the anonymous struct literal’s value.
Helper function (no receiver)
package main
import "fmt"
func printPerson(p struct {
Name string
Age int
}) {
fmt.Printf("%s is %d\n", p.Name, p.Age)
}
func main() {
printPerson(struct {
Name string
Age int
}{"John", 30})
}You should see John is 30.
Embed a named type with methods
Here the outer literal is still anonymous, but the behavior comes from a named embedded type:
package main
import "fmt"
type greeter struct{}
func (greeter) Hello() string { return "hi" }
func main() {
v := struct {
greeter
Name string
}{Name: "Ada"}
fmt.Println(v.Hello(), v.Name)
}You should see hi Ada (promoted method from the embedded field).
Anonymous struct vs anonymous field
These phrases sound similar but mean different things:
| Phrase | Meaning |
|---|---|
| Anonymous struct | The struct type has no type name; it is spelled inline. |
| Anonymous field (embedding) | A struct field declared with only a type name, no field identifier—the promoted name is the type name. |
An anonymous struct can contain embedded (anonymous) fields of named types, which is how the previous greeter example picked up Hello.
Mistakes to avoid
Pasting the same large anonymous struct literal in many functions instead of promoting one named type.
Deep nesting of anonymous structs—readability drops quickly; name inner shapes.
Expecting receiver methods on the literal type itself—declare a named type at package scope instead.
Using anonymous structs in exported APIs where callers depend on the exact field set—named types version more clearly.
Anonymous struct cheat sheet
| Situation | Better choice |
|---|---|
| One-time local shape | Anonymous struct |
| Table-driven cases | Slice of anonymous structs |
| Small JSON body used once | Tagged anonymous struct |
| Reused layout across packages | Named struct |
| Public API surface | Named struct |
| Need methods on the receiver | Named struct |
| One-off behavior | Function taking the struct |
| Want promoted methods on a literal | Embed a named type |
| Deep nested JSON | Named types for sub-objects |
Summary
Anonymous structs in Go are inline struct types: struct { fields }{values}, also called unnamed or inline structs. They shine in table-driven tests, compact JSON decode shapes, and small return bundles. Returning struct{...} from a function is legal but named types read better at package boundaries. For golang anonymous struct with method expectations, remember that methods bind to defined receiver types at package scope—use helpers, embedding, or a named type instead of a method on the literal itself. Embedding is about anonymous fields, not anonymous struct names. When the same shape repeats or the API is exported, switch to a named struct.

