How to Find the Type of an Object in Go: 5 Fatal Beginner Mistakes and How to Avoid Them

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: "What kind of beast is this?"

\n\n

Imagine: you are writing a Go function that takes an interface{}. Inside this function, you want to understand what kind of data came to you. A number? A string? Or maybe some custom struct? If you come from Python or JavaScript, where you can find out the type in one line (type() or typeof), then in Go you are in for a small surprise. Go is a strictly typed language, and you can't just "feel" the type of an object.

\n\n

The question "How to find the type of an object in Go?" on Stack Overflow has gathered tens of thousands of views. This means that even experienced developers sometimes get confused. In this article, we will look at the top mistakes that beginners (and not only) make when determining a type in Go, and show how to avoid them. You will learn about reflect.TypeOf, fmt.Sprintf with %T, type assertion, and type switch.

\n\n

Method #1: The Simplest — fmt and %T (but with a catch)

\n\n

The fastest way to find out the type is to use the fmt package and the %T format. This works, but many forget that fmt is not a magic wand, but just a wrapper over reflect.

\n\n
package main\n\nimport "fmt"\n\nfunc main() {\n    var x interface{} = 42\n    fmt.Printf("Type: %T\\n", x) // Type: int\n\n    var s interface{} = "hello"\n    fmt.Printf("Type: %T\\n", s) // Type: string\n}\n
\n\n

Simple, right? But here's the mistake: %T returns a string, not a type. You cannot perform any operations with it other than printing it to the screen. If you need to check whether an object is a number and do something with it — %T won't help you. This is the first mistake: using %T where branching logic is needed.

\n\n

How to avoid it

\n

Use %T only for debugging or logging output. For type checking in code, use type assertion or type switch (more on these below).

\n\n

Method #2: The reflect Package — Powerful but Dangerous

\n\n

The reflect package is the gentleman's set for reflection in Go. The most popular method is reflect.TypeOf().

\n\n
package main\n\nimport (\n    "fmt"\n    "reflect"\n)\n\nfunc main() {\n    var x interface{} = 42\n    t := reflect.TypeOf(x)\n    fmt.Println(t) // int\n    fmt.Println(t.Name()) // int\n    fmt.Println(t.Kind()) // int\n}\n
\n\n

It seems like the perfect solution. But here beginners make the second mistake: confusing Kind() and Name().

\n\n
    \n
  • Name() — returns the type name (e.g., int, string, MyStruct).
  • \n
  • Kind() — returns the base "kind" (e.g., int, struct, slice).
  • \n
\n\n

For built-in types they match, but for custom types — they don't. For example, if you declare type MyInt int, then Name() will return MyInt, and Kind() will return int. If you only check Kind(), you might miss a custom type.

\n\n

How to avoid it

\n

Always ask yourself: "Do I need the exact type or just the category?" If you need the exact type (e.g., for serialization) — use Name(). If you just need to understand that it's a number — use Kind().

\n\n

Method #3: Type Assertion — A Classic (and a Panic Error)

\n\n

Type assertion is a way to "extract" a specific type from interface{}. It looks like this:

\n\n
package main\n\nimport "fmt"\n\nfunc main() {\n    var x interface{} = 42\n    value := x.(int) // assert that x is an int\n    fmt.Println(value + 10) // 52\n}\n
\n\n

What's the mistake? If x turns out

Blogs

Book Recommendations