What is the main differences between :
v = t.(aType) // type assertion
v = aType(t) // type conversion
Where should I use type assertion or type conversion ?
In Typescript, Type assertion is a technique that informs the compiler about the type of a variable. Type assertion is similar to typecasting but it doesn't reconstruct code. You can use type assertion to specify a value's type and tell the compiler not to deduce it.
In computer science, type conversion, type casting, type coercion, and type juggling are different ways of changing an expression from one data type to another. An example would be the conversion of an integer value into a floating point value or its textual representation as a string, and vice versa.
Type conversion (or typecasting) means transfer of data from one data type to another. Implicit conversion happens when the compiler (for compiled languages) or runtime (for script languages like JavaScript) automatically converts data types. The source code can also explicitly require a conversion to take place.
Type assertions in Golang provide access to the exact type of variable of an interface. If already the data type is present in the interface, then it will retrieve the actual data type value held by the interface. A type assertion takes an interface value and extracts from it a value of the specified explicit type.
A type assertion asserts that t
(an interface type) actually is a aType
and t
will be an aType
; namely the one wrapped in the t
interface. E.g. if you know that your var reader io.Reader
actually is a *bytes.Buffer
you can do var br *bytes.Buffer = reader.(*bytes.Buffer)
.
A type conversion converts one (non-interface) type to another, e.g. a var x uint8
to and int64 like var id int64 = int64(x)
.
Rule of thumb: If you have to wrap your concrete type into an interface and want your concrete type back, use a type assertion (or type switch). If you need to convert one concrete type to an other, use a type conversion.
tl;dr x.(T)
asserts that the dynamic value of interface x
is T
at run time; T(x)
converts the type of an expression x
to some other type.
You know that in Go an interface is basically a method set specification, and you can assign to an interface variable any value whose type implements that method set1.
The type assertion written x.(T)
asserts that the value stored in the interface x
is of type T
. You use a type assertion when you want to unbox that value.
One of the most common uses is when you have interface{}
and you need to retrieve the concrete value it stores. A typical example, Context
values:
func foo(ctx context.Context) {
s := ctx.Value("my_key").(string) // signature is `Value(key interface{}) interface{}`
// do something with s...
}
It is called assertion because at compile time it is not known whether x
actually holds the concrete type T
, but you assert that it does.
That's why the unchecked assertion y := x.(T)
panics if x
doesn't actually hold a T
— you must use the comma-ok assignment v, ok := x.(T)
to avoid it.
ctx = context.WithValue(ctx, "my_key", "foo")
s := ctx.Value("my_key").(int) // panic
v, ok := ctx.Value("my_key").(string)
fmt.Println(v, ok) // "foo" true
In addition, when T
in x.(T)
is an interface itself, the assertion checks that the value stored in x
implements T
. The outcome is the same as above.
A type conversion written as T(x)
instead "changes the type of an expression to the type specified by the conversion", i.e. changes the type of x
to T
. An important property of conversions is that they are statically checked2. An invalid conversion simply won't compile:
type Foo string
type Bar int
a := "foo"
fmt.Println(Bar(a)) // cannot convert a (type string) to type Bar
The main condition for a conversion to be valid is assignability between the types involved, but there's several more, including conversions between numerical types, strings and byte/rune slices, directed channels, slices and array pointers, etc.
In simple terms, you use a conversion when you already know what are the types involved, and simply want to change one to the other:
b := []byte("foo") // converts string literal to byte slice
Notes:
1: more formally, when the value's method set is a superset of the interface method set; this is also why the empty interface interface{}
can hold any value, because any set is a superset of an empty set.
2: type assertions are also checked at compile time when the type T
in x.(T)
does not implement the interface. In practice, this won't help you catch errors when x
is interface{}
since all types implement it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With