skip to content

What do reflect.TypeOf and reflect.ValueOf return, and how do you get an ordinary Go value back?

level: juniorimportance: must knowfreq 48%

answer

  1. two entry points, two different nouns
  2. one describes shape, one holds data
  3. both parameters are declared any
  4. Interface() is the door back out
  5. then a type assertion names the type

basics

~20 s

reflect.TypeOf returns a reflect.Type describing the dynamic type of whatever you pass it; reflect.ValueOf returns a reflect.Value wrapping the data itself. Value.Interface() hands the data back as an any, which you then type-assert to a concrete type.

solid answer

~40 s

Both take a parameter of type `any`, so the concrete value you pass is boxed into an interface first, and reflection reads the dynamic type and data out of that interface. `reflect.TypeOf(x)` gives you a `reflect.Type` — the shape: its `Kind`, its declared `Name`, its methods and fields. `reflect.ValueOf(x)` gives you a `reflect.Value` — a handle on the data, with typed accessors like `Int()`, `Float()` and `Len()` whose legality depends on the value's `Kind`. The trip back out is `Value.Interface()`, which returns an `any` you type-assert: `n := v.Interface().(int)`. Two consequences worth saying out loud: the value is copied on the way in, and `Interface()` panics if the `reflect.Value` was obtained by reading an unexported struct field, which `CanInterface()` reports up front.

code

go · 10 lines
go
var x float64 = 3.4

t := reflect.TypeOf(x)
v := reflect.ValueOf(x)

fmt.Println(t.Kind()) // float64
fmt.Println(v.Kind()) // float64

back := v.Interface().(float64)
fmt.Println(back) // 3.4

go deeper

for a junior

Be ready to name both entry points and say which one describes the type and which one holds the data, then show the way back with Interface() plus a type assertion.

for a middle

Explain that both parameters are declared any, so the argument is boxed and reflection reads the dynamic type out of the interface, and that the value is copied on the way in.

for a senior

Show the guards a real walker needs: check Kind before calling a typed accessor, and check CanInterface before Interface, so a value read from an unexported field does not panic your inspector.

for a principal

Be able to argue when reflection is the right tool at all, versus type parameters or generated code, and what a reflective boundary costs a team in readability and in run-time overhead.

## Why the package exists Go is statically typed: normally the compiler knows the type of every expression, and code that wants to branch on a type does it with a type switch or a type assertion, both of which require you to *name* the types at compile time. Reflection is for the cases where you cannot: a JSON encoder, a struct-to-row mapper, a table-driven test helper, an interactive inspector that prints whatever value the session just evaluated. Those need to ask, at run time, "what am I holding, and what is inside it?" The `reflect` package answers that with two objects and two entry points. ## reflect.TypeOf — the shape `reflect.TypeOf(i any) reflect.Type` returns a description of the *dynamic* type of the value inside the interface you passed. `reflect.Type` is an interface with methods such as `Kind()` (which of the roughly two dozen built-in categories this is: `Int`, `Slice`, `Struct`, `Pointer`, `Map`, …), `Name()` (the declared name, empty for unnamed composite types), `String()` (a readable package-qualified form), plus the structural methods — `NumField`, `Elem`, `NumMethod` and friends. A `reflect.Type` value is canonical: the runtime hands out one descriptor per type, so two `reflect.Type` values are `==` exactly when they describe the same type. That makes `reflect.TypeOf(x) == reflect.TypeOf(time.Time{})` a legitimate identity test. ## reflect.ValueOf — the data `reflect.ValueOf(i any) reflect.Value` returns a handle on the data itself. A `reflect.Value` is a struct (not an interface), and it carries three things internally: which type it is, where the data is, and a set of flags. From it you can ask `Kind()`, `Type()`, `Len()`, `Index(i)`, `MapKeys()`, `Int()`, `Float()`, `Bool()` and so on — but each typed accessor is only legal for the matching `Kind`, and calling the wrong one panics. `Kind()` is therefore the gate you check before you read. Note that the value is *copied* on the way in. Passing `x` to `ValueOf` boxes a copy into the `any` parameter, so the `reflect.Value` you get back refers to that copy, not to your variable. ## The round trip back `Value.Interface() any` is the door out of reflection and back into ordinary Go: ```go v := reflect.ValueOf(3.4) back := v.Interface().(float64) // 3.4 ``` The assertion is required because `Interface()` is typed `any` — reflection can tell you at run time that the dynamic type is `float64`, but the compiler still needs you to state the static type you want. If you get it wrong, the assertion panics (or returns `ok == false` in the two-result form). One restriction: `Interface()` panics with "cannot return value obtained from unexported field or method" when the `reflect.Value` was read out of an unexported struct field. Reflection is allowed to *look at* such fields, but handing their contents back to normal code would let any package sidestep another package's encapsulation, so the value is flagged read-only. `CanInterface()` tells you in advance whether the call is safe. ## How the pieces line up For any value `x`, all of the following hold: - `reflect.TypeOf(x)` and `reflect.ValueOf(x).Type()` describe the same type. - `reflect.ValueOf(x).Kind()` and `reflect.TypeOf(x).Kind()` are the same `Kind`. - `reflect.ValueOf(x).Interface()` restores an `any` equal to `x`. So `Type` is the noun that answers "what shape", `Value` is the noun that answers "what data", and `Kind` is the coarse category both of them expose. ## Practical shape of inspector code Most reflection code is a small loop of the same three moves: get a `Value`, switch on its `Kind` to decide how to read it, and either recurse into its parts or call `Interface()` to hand a leaf back to ordinary code. Everything else in the package is a variation on that. And because each of those steps is a run-time lookup rather than a compiled-in offset, reflective code is measurably slower than the equivalent statically typed code — worth remembering before you reach for it on a hot path. ## What to say in an interview Name both entry points, say that both take `any` so the argument is boxed first, say that `Type` is the shape and `Value` is the data, and finish with `Interface()` plus a type assertion as the way back. Mentioning that the value is copied, and that `Interface()` refuses values read from unexported fields, is what separates a memorised answer from a used-it answer.

  • Why are the parameters of reflect.TypeOf and reflect.ValueOf declared as any rather than a type parameter?
    Because reflection deliberately works on values whose type is unknown at compile time. Declaring `any` boxes whatever you pass into an interface, and `reflect` then reads the dynamic type and data out of that interface. A side effect is that a `reflect.Value` from `ValueOf` never reports `Kind` `Interface` — the interface wrapper is unwrapped on the way in, and you see the concrete type it held.
  • When does Value.Interface() panic?
    When the `reflect.Value` was obtained by reading an unexported struct field. Such values carry a read-only flag, because handing their contents out as an `any` would let any package bypass another package's encapsulation. `CanInterface()` reports whether the call is safe, so a general-purpose walker checks it before calling.
  • How is this different from a plain type assertion like x.(float64)?
    A type assertion requires you to name the type in source, so it only works for types you knew about when you wrote the code, and it is far cheaper. Reflection works when the type is not known until run time — a generic encoder, a mapper, an inspector — at the cost of run-time lookups instead of compiled-in offsets.

reflect.Type is the blueprint and reflect.Value is the object built from it. Interface() is the door out of the workshop and back into ordinary Go, where you still have to say aloud which type you are carrying.

saying these in an interview costs you the question

  • Says reflect.ValueOf returns the value's memory address
  • Claims Value.Interface() returns a string
  • Uses a reflect.Value directly in arithmetic
  • Confuses reflect.Type with the Kind category
  • Thinks reflection mutates the original variable by default