Type assertions and type switches in Golang
Go focuses on static typing, ensures type safety, and prevents runtime errors. But what if we need to work with data whose type might be unknown at compile-time? In this situation, type assertions and type switches come in handy!
In Go interfaces, powerful constructs define a set of methods a type must implement. An interface variable can hold a value of any type that implements the interface. This flexibility is crucial when dealing with dynamic data.
Type assertions
A type assertion allows us to extract the underlying concrete value from an interface variable, assuming it holds the type:
value, ok := interface_type.(string)
interface_typeis an interface for which we want to check the type assertion.valuecontains the return type of the interface.okis a variable that holds any error that might occur during type assertion.
Note:
Incorrect type assertion: Asserting to the wrong type will cause a panic at runtime. Always check the
okvalue before using the asserted variable.Type safety: Type assertions bypass static type checking. Use them cautiously and only when necessary.
Example: Type assertion
Click the “Run” button to execute the example:
package mainimport "fmt"func main() {var i interface{} = "hello"// Type assertionstr, ok := i.(string)if ok {fmt.Println("String:", str)} else {fmt.Println("Not a string")}// Type assertion with wrong type_, ok = i.(int)if !ok {fmt.Println("Not an integer")}}
Line 6: Here, we declare a variable
iof typeinterface{}. This means thatican hold any type of value sinceinterface{}is the empty interface in Go, which specifies zero methods.Line 9: We perform a type assertion on the variable
i. We check whether the dynamic type ofiis a string or not. If the assertion holds true, the underlying value ofiis assigned to the variablestr, andokwill betrue. If the assertion fails,strwill be assigned the zero value of the string type, andokwill befalse.Lines 10–14: We use the boolean variable
okto determine whether the type assertion succeeded or not. Ifokistrue, it means thatiis indeed a string, so we print out the value ofstrusingfmt.Println("String:", str). Otherwise, ifokisfalse, it means thatiis not a string, so we print out “Not a string.”Line 17: This line performs another type assertion on the variable
i, this time checking ifiis of typeint. Since we’re not interested in the actual value (if any), we use the blank identifier_to discard it. We assign the result of the type assertion tookagain.Lines 18–20: Here, we check if
okisfalse, meaning that the type assertion failed. If so, we print out “Not an integer,” indicating that the value held byiis not an integer.
Type switches
A type switch is a control flow structure specifically designed for working with interfaces. It performs a series of type assertions in a more structured way. It allows testing the interface value against multiple types, executing the corresponding case block for the first matching type:
switch variable.(type) {case type1:// Code to handle type1case type2:// Code to handle type2default:// Code to handle unknown type}
variableis the interface whose type needs to be checked.In this switch statement, we have three cases;
type,type2, anddefault. The matching case will be executed based on the type of interface.
Example: Type switches
Click the “Run” button to execute the example:
package mainimport "fmt"func doSomething(i interface{}) {switch v := i.(type) {case int:fmt.Println("Double of integer:", v*2)case string:fmt.Println("Length of string:", len(v))default:fmt.Println("Unknown type")}}func main() {doSomething(10) // Output: Double of integer: 20doSomething("hello") // Output: Length of string: 5doSomething(3.14) // Output: Unknown type}
Line 5: The
doSomethingfunction takes an empty interface (interface{}) as a parameter. This means thatican hold values of any type.Line 6: This is a type switch statement. It checks the type of the interface value
idynamically and assigns the value ofito a new variablevwhose type is determined by the type ofi. The keywordtypeis used within the switch statement to indicate that it’s a type switch. Eachcasewithin the switch statement checks against a specific type.Lines 7–8: If the type of
iisint, this case block is executed. In this case, it prints “Double of integer:” followed by the doubled value ofv.Lines 9–10: If the type of
iisstring, this case block is executed. It prints “Length of string:” followed by the length of the stringv.Lines 11–12: If the type of
idoesn’t match any of the specified cases, thedefaultcase is executed. It prints “Unknown type.”Line 16: This is the
main()function where the program execution starts.Line 17: This calls the
doSomethingfunction with an integer value10as an argument. Since10is an integer, the first case block (case int) is executed, printing “Double of integer: 20.”Line 18: This calls the
doSomethingfunction with a string value"hello"as an argument. Since"hello"is a string, the second case block (case string) is executed, printing “Length of string: 5.”Line 19: This calls the
doSomethingfunction with a floating-point value3.14as an argument. Since3.14is neither an integer nor a string, thedefaultcase is executed, printing “Unknown type.”
Comparison between Type Assestions and Type Switches
Aspect | Type Assertions | Type Switches |
Purpose | Test and extract the underlying type of an interface | Perform conditional logic based on interface type |
Usage | Used when specific type information is required | Ideal for scenarios with multiple type possibilities |
Handling non-existent types | Requires additional error checking (the | Automatically handles non-existent types |
Error handling | Requires explicit handling for non-matching types | Simplifies handling with default case in switch |
Type information | Extracts and provides access to specific type | Allows direct access to type within case statements |
Readability | May require additional error handling, less concise | Provides clearer and more concise code structure |
Flexibility | Offers fine-grained control over type extraction | Enables concise and structured type-based branching |
Conclusion
Type assertions and type switches are essential tools for working with interfaces in Go. They provide flexibility and allow for dynamic type handling, enabling developers to write more expressive and concise code. By mastering these concepts, a developer will be better equipped to design robust and efficient Go programs.
Unlock your potential: Golang series, all in one place!
To continue your exploration of Golang, check out our series of Answers below:
What is the NewReplacer function in golang?
Learn how Go'sstrings.NewReplacer()efficiently replaces multiple substrings in a single pass, avoiding sequential replacements.Type Assertions and Type Switches in Golang
Learn how type assertions and type switches in Go enable dynamic type handling within interfaces, ensuring type safety and flexibility for robust and efficient programming.What is the fan-out/fan-in pattern in Golang
Learn how the fan-out/fan-in pattern in Go parallelizes tasks using goroutines and channels, enabling concurrent execution and efficient result aggregation.Getting Started with Golang Unit Testing
Learn how to perform unit testing in Go by creating_test.gofiles, using thetestingpackage, and writing clear test cases.How to parse xml file to csv using golang with dynamic shcema?
Learn how to use Go'sencoding/xmlandencoding/csvpackages to dynamically convert XML files to CSV.
Free Resources