What does reflect.New(t) return in Go, and why do you call Elem() on the result?
answer
- it is the runtime form of a builtin
- you always get one extra level of indirection
- the Kind you get back is Pointer
- dereferencing is a method, not an operator
- Interface() plus a type assertion gets you out
basics
~20 sreflect.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 linestype 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
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.
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.
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.
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