Conversion of type parameters

March 4, 2024

Today I’ll be live-streaming again, doing TDD on an open-source project. I hope you can join!


Conversions

Additionally, if T or x’s type V are type parameters, x can also be converted to type T if one of the following conditions applies:

  • Both V and T are type parameters and a value of each type in V’s type set can be converted to each type in T’s type set.
  • Only V is a type parameter and a value of each type in V’s type set can be converted to T.
  • Only T is a type parameter and x can be converted to each type in T’s type set.

So in other words, conversion to/from a type parameter is not possible if there’s a possibility that the conversion would be impossible.

Let’s illustrate with examples.

func foo[T int | int8, V int | int16](x V) T {
	return T(x) // Allowed, All types of V can be converted to all types of T
}

func foo2[T int | int8, V int | int16 | string](x V) T {
	return T(x) // Not allowed: cannot convert x (variable of type V constrained by int | int16 | string) to type T: cannot convert string (in V) to type int (in T)
}

func bar[V int | int16] (x V) int {
	return int(x) // Allowed: Each type of V can be converted to int
}

func bar2[V int | int16] (x V) bool {
	return bool(x) // Not allowed: cannot convert x (variable of type V constrained by int | int16) to type bool: cannot convert int (in V) to type bool
}

func baz[T int | int8] (x int) T {
	return T(x) // Allowed: x can be converted to each of T's types
}

func baz2[T int | int8 | bool] (x int) T {
	return T(x) // Not allowed: cannot convert x (variable of type int) to type T: cannot convert int to type bool (in T)
}

Quotes from The Go Programming Language Specification Language version go1.22 (Feb 6, 2024)


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Related Content


Type switches with generics

More live coding today! Join me! And bring your questions. Type switches … A type parameter or a generic type may be used as a type in a case. If upon instantiation that type turns out to duplicate another entry in the switch, the first matching case is chosen. func f[P any](x any) int { switch x.(type) { case P: return 0 case string: return 1 case []P: return 2 case []byte: return 3 default: return 4 } } var v1 = f[string]("foo") // v1 == 0 var v2 = f[byte]([]byte{}) // v2 == 2 The example included is nice, because it shows two examples of the type parameter P being used: Both the first case (case P) and third (case []P) use the type parameter.


Type switching on a non-interface value. Sorta.

Type switches … Cases then match actual types T against the dynamic type of the expression x. As with type assertions, x must be of interface type, but not a type parameter, and each non-interface type T listed in a case must implement the type of x. The types listed in the cases of a type switch must all be different. TypeSwitchStmt = "switch" [ SimpleStmt ";" ] TypeSwitchGuard "{" { TypeCaseClause } "}" .


Switch expressions

Expression switches … If the switch expression evaluates to an untyped constant, it is first implicitly converted to its default type. The predeclared untyped value nil cannot be used as a switch expression. The switch expression type must be comparable. In this paragraph, “switch expression” refers to the expression that optionally comes after the switch keyword, as in: switch len(x) { So first off, if it’s a untyped constant, it’s first converted to its default type.

Get daily content like this in your inbox!

Subscribe