skip to content

Building Values Dynamically

A decoder has to allocate the thing it is decoding into before it can set anything: reflect.New hands back an addressable value, MakeSlice and MakeMap hand back containers, and Zero the empty one.

part ofGo (Golang)overview, primer and where to startread it →
on this pageshow

questions

4

What does reflect.New(t) return in Go, and why do you call Elem() on the result?

level: juniorimportance: must knowfreq 34%

answer

  1. it is the runtime form of a builtin
  2. you always get one extra level of indirection
  3. the Kind you get back is Pointer
  4. dereferencing is a method, not an operator
  5. Interface() plus a type assertion gets you out

basics

~20 s

reflect.New(t) allocates a zero value of type t and returns a reflect.Value holding a pointer to it, exactly like new(T). Elem() follows that pointer to the value itself, which lives in addressable memory and can be filled in.

solid answer

~40 s

`reflect.New(t)` is the runtime equivalent of `new(T)`: it allocates fresh storage holding the zero value of `t` and returns a `reflect.Value` whose `Kind()` is `reflect.Pointer` and whose type is `*t`. You almost never want that pointer handle directly, so you call `Elem()` on it, which dereferences one level and gives you a `reflect.Value` for the allocated value itself. That Elem value sits in memory the reflection package owns, so it is addressable and can be written into; a value obtained from `reflect.ValueOf(x)` is a copy and cannot. When the value is built, you go back to ordinary Go with `Interface()` plus a type assertion: `p.Interface().(*Config)` for the pointer, or `p.Elem().Interface().(Config)` for a copy of the value.

code

go · 12 lines
go
type Config struct {
	Retries int
	Name    string
}

func newConfigPtr() any {
	t := reflect.TypeOf(Config{})
	p := reflect.New(t) // Kind is reflect.Pointer, type is *Config
	v := p.Elem()       // Kind is reflect.Struct, addressable
	v.Field(0).SetInt(3)
	return p.Interface() // any holding *Config{Retries: 3}
}

go deeper

for a junior

Be ready to say the two steps out loud: reflect.New(t) gives a pointer Value, Elem() gives the value it points at. Know that everything starts as the zero value and that Interface() plus a type assertion gets you back to ordinary Go.

for a middle

Explain why the pointer exists at all: reflect.ValueOf copies, so only memory reflection allocated or was handed the address of can be written. Know that Elem is valid on pointers and interfaces and panics elsewhere.

for a senior

Show the boundary discipline in real code: reflect.Value stays inside the package, Interface() converts at the edge, and the type assertion failure is handled rather than left to panic in a caller's request path.

for a principal

Frame when a dynamically constructed value is worth it at all against a code generator or type parameters, since every reflect.New path is a place the compiler stops checking your work and a test has to.

## The two reflection handles The `reflect` package gives you two things to hold a program's types and values at runtime. A `reflect.Type` describes a type: its kind, its name, its fields, its methods. A `reflect.Value` is a handle on an actual value together with its type. You enter reflection with `reflect.TypeOf(x)` and `reflect.ValueOf(x)`, and you leave it with `Value.Interface()`, which returns an `any` you type-assert back to a concrete type. That covers inspecting values you were handed. Constructing a value whose type you only learned at runtime is a different job, and `reflect.New` is the entry point for it. ## reflect.New is `new(T)` for a type you do not know at compile time The signature is `func New(typ Type) Value`. It allocates storage for one zero value of `typ` and returns a `reflect.Value` representing a **pointer** to that storage. If `typ` describes `Config`, the returned value's dynamic type is `*Config` and its `Kind()` is `reflect.Pointer`. It is the exact runtime analogue of writing `new(Config)` in source. Passing a nil `reflect.Type` panics. The allocated value starts as the zero value of the type, all the way down: numeric fields are `0`, strings are `""`, booleans are `false`, and pointers, slices, maps, channels, functions and interfaces are `nil`. Struct and array elements are zeroed recursively. ## Why you get a pointer, and what Elem() is for The pointer is not an inconvenience; it is the whole point. Reflection can only write into memory it can take the address of. `reflect.ValueOf(cfg)` copies `cfg` into an interface, so the `reflect.Value` you get back refers to a copy the caller can never see — writing into it would be meaningless, and the package forbids it. By allocating the value itself, `reflect.New` guarantees the storage is addressable. `Value.Elem()` is the reflection form of the `*` dereference operator. On a `reflect.Value` of `Kind` `Pointer` it returns a handle on the pointed-to value; on a `Kind` `Interface` it returns the dynamic value stored inside the interface. On anything else — a struct, an int, a slice — it **panics**. So the idiom is always two steps: ``` p := reflect.New(t) // Kind Pointer, type *T v := p.Elem() // Kind of T, addressable ``` Asking `p.NumField()` directly is a classic beginner panic: `p` is a pointer, not a struct. ## The round trip back to ordinary Go A `reflect.Value` is not something you want to hand to callers of a normal API. Convert it back: - `p.Interface()` returns an `any` whose dynamic type is `*T`; assert it with `.(*Config)`. - `p.Elem().Interface()` returns an `any` holding a **copy** of the value; assert it with `.(Config)`. If the caller passed you a destination — the common shape for a decoder or a fixture loader, `func Fill(dst any) error` — you instead do `reflect.ValueOf(dst).Elem()` to get an addressable handle on their variable, and `reflect.New` is only needed for the sub-values you allocate along the way. ## Where it shows up A library that builds test fixtures or decodes into an unknown type does the same dance the standard library's own decoders do: take a `reflect.Type` for the target, `reflect.New` it, walk its structure filling values in, then return `p.Interface()` to the caller. Because everything starts zeroed, the builder only has to write the fields it actually has data for. ## Pitfalls worth naming - **Forgetting the extra level of indirection.** `reflect.New(t)` is a pointer. Every field walk, every `Set`, every `Len` happens on `Elem()`. - **Calling `Elem()` twice.** `p.Elem().Elem()` panics unless `T` is itself a pointer or interface type. - **Reaching for `reflect.Zero(t)` instead.** `reflect.Zero` also gives you a zero value of `t`, but it is read-only: not addressable and not settable. When you intend to fill something in, `reflect.New(t).Elem()` is the one you want. - **Leaking `reflect.Value` into the public API.** Convert with `Interface()` at the boundary; callers should never have to import `reflect` to use your builder. - **Assuming a zeroed map or channel is usable.** `reflect.New` of a map type gives you a pointer to a *nil* map, which panics on write. Reference kinds need `reflect.MakeMap`, `reflect.MakeChan` or `reflect.MakeSlice` instead.

  • Once you have filled the value in, how do you hand it back to a caller who does not import reflect?
    Call `Interface()` at the boundary. `p.Interface()` returns an `any` whose dynamic type is `*Config`, so the caller type-asserts `.(*Config)`; `p.Elem().Interface()` returns a copy as `any` holding `Config`. Never return a `reflect.Value` from a public API — it forces every caller into the reflect package and exposes an internal representation you may want to change.
  • How is reflect.New(t) different from reflect.Zero(t)?
    `reflect.New(t)` allocates storage and returns a pointer Value; its `Elem()` is addressable, so you can write into it. `reflect.Zero(t)` allocates nothing and returns a Value of type `t` directly, explicitly documented as neither addressable nor settable. Use `Zero` when you need a blank to read or pass along, and `New(t).Elem()` when you need something to fill in.
  • What happens if you call Elem() on the reflect.Value for a struct rather than a pointer?
    It panics. `Elem` is only defined for `Kind` `Pointer`, where it dereferences, and `Kind` `Interface`, where it returns the dynamic value inside. On a struct, an int or a slice it is a programming error. Guard with `v.Kind() == reflect.Pointer` when the type came from somewhere you do not control.

saying these in an interview costs you the question

  • Says reflect.New returns the value, not a pointer to it
  • Calls Elem() on a Value that is not a pointer or interface
  • Uses reflect.Zero(t) when the value must be filled in
  • Returns raw reflect.Value from a library's public API
  • Thinks reflect.New defers allocation until first write
open as a page

Why does reflect.New(mapType).Elem() give an unusable map in Go, and what should you use?

level: middleimportance: should knowfreq 38%

basics

~20 s

The zero value of a map type is a nil map, and reflect.New only ever gives you the zero value, so writing an entry panics. Use reflect.MakeMap for maps, reflect.MakeSlice for slices and reflect.MakeChan for channels.

open as a page

A builder calls reflect.MakeSlice(t, n, n), then reflect.Append(s, v) in a loop, yet the result holds n zero values and none of the appended ones. What are the two bugs?

level: seniorimportance: should knowfreq 34%

basics

~20 s

reflect.MakeSlice takes length second and capacity third, so MakeSlice(t, n, n) starts with n zero elements; it should be MakeSlice(t, 0, n). And reflect.Append returns a new Value, so its result must be assigned back.

open as a page

In Go's reflect package, how does reflect.Zero(t) differ from Value.IsZero()?

level: middleimportance: nice to knowfreq 26%

basics

~20 s

reflect.Zero(t) constructs a value: the zero value of type t, explicitly not addressable and not settable. Value.IsZero() inspects a value and reports whether it already equals the zero value of its own type. One builds, one asks.

open as a page