When would you use Struct Literal And Fields in a real project
Fast recall
Quick revision
Core answer
Practical understanding of Struct Literal And Fields.
Repeating a definition without saying when to use it.
Give one trade-off and say how you would test it.
Interview-ready guide
Interview answer
Export is case, and case is the whole mechanism:
package billing
type Invoice struct {
ID string // exported: billing.Invoice.ID works anywhere
total float64 // unexported: invisible outside billing
}Outside the package, invoice.ID compiles; invoice.total does not — the selector on an unexported field is a compile error ('cannot refer to unexported field total').
The pattern this forces — and it's the architecture of half the standard library: unexported fields + exported accessors. time.Time is the exhibit: ALL fields unexported, all access through methods (Year(), Unix()...). Two reasons to do this, both structural:
- 1
Invariants: if total must never be negative (or must equal items-sum), exported access breaks any rule you can't enforce. Unexported + a SetTotal method that validates = the invariant lives in one place. Any exported field is a hole in the invariant's enforcement — no contract survives a direct write.
- 2
Freedom to change: unexported fields are implementation. You can rename, retype, restructure them without breaking any importer — the package's API (methods) is the only contract. An exported field is public API forever — changing its type is a breaking change.
What Go deliberately does NOT have: getter/setter syntax sugar (no properties), field visibility beyond the two levels (no protected, no internal-by-assembly). The result: the decision 'export or not' is the one visibility decision, made per identifier, and its consequences are total. The idiom that follows — exported struct = value object with plain fields (fmt's structs, config DTOs); unexported fields + methods = stateful object with invariants (time.Time, strings.Builder) — is the style guide written in case choices.
When would you use Struct Literal And Fields in a real project
Direct Answer
Capitalized names are exported — visible to other packages via the selector. Lowercase are unexported — package-private. This is THE visibility boundary in Go: one rule, applied to fields, methods, types, functions.
Deep Dive & Architecture
The mechanics of the selector rule: the compiler resolves x.total at the USE site's package. If the field's defining package differs and the name starts lowercase — undefined selector — a compile-time error, not a runtime hide. That's why 'unexported' means invisible, not inaccessible — the compiler simply has no path to the field from other packages (the symbol isn't in the package's export data).
The escape hatch people ask about and should know exists but rarely use: unsafe — unsafe.Pointer arithmetic can reach unexported fields (the implementation detail that gorm/encoding libraries sometimes leverage for performance). It's outside the type system's guarantees — 'unsafe' is the honest name — and any code doing it owns the breakage when layouts change.
The JSON interplay, because it's where the rule bites daily: encoding/json uses exported fields only. A struct with all-unexported fields serializes to {}. The workarounds — exported fields with json tags, or an exported DTO mirroring the domain struct, or MarshalJSON implemented manually — are the standard architectural choice points. The visibility rule and the serialization framework meet exactly here, and the 'domain struct + wire DTO' split is the clean answer when both needs are real.
The comparison that frames why Go's single rule is defensible: Java's four levels (public/protected/package/private) plus default-package semantics create a decision space per member; Go collapses it to one bit (uppercase or not). The cost: no 'visible to subpackage but not the world' — Go has no subpackage concept. The benefit: the visibility question is answerable by looking at ONE character of the name, and import cycles can't be partially broken by 'internal' visibility games. When teams need layered visibility, Go's answer is architecture (interfaces, small packages) — not finer-grained keywords.
Common Mistakes & Pitfalls
Repeating a definition without saying when to use it.
Check your understanding
Answer these without looking back at the article.
- What is Struct Literal And Fields, and when would you use it?
- How would you compare Struct Literal And Fields with an alternative?
- What is a common mistake when using Struct Literal And Fields?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.