Arithmetic operators
Arithmetic operators apply to numeric values and yield a result of the same type as the first operand. The four standard arithmetic operators (
+
,-
,*
,/
) apply to integer, floating-point, and complex types;+
also applies to strings. The bitwise logical and shift operators apply to integers only.+ sum integers, floats, complex values, strings - difference integers, floats, complex values * product integers, floats, complex values / quotient integers, floats, complex values % remainder integers & bitwise AND integers | bitwise OR integers ^ bitwise XOR integers &^ bit clear (AND NOT) integers << left shift integer << integer >= 0 >> right shift integer >> integer >= 0
There should be nothing surprising here. Things get only slightly more interesting when we consider the use of arithmetic operators and generics…
If the operand type is a type parameter, the operator must apply to each type in that type set. The operands are represented as values of the type argument that the type parameter is instantiated with, and the operation is computed with the precision of that type argument. For example, given the function:
func dotProduct[F ~float32|~float64](v1, v2 []F) F { var s F for i, x := range v1 { y := v2[i] s += x * y } return s }
the product
x * y
and the additions += x * y
are computed withfloat32
orfloat64
precision, respectively, depending on the type argument forF
.
This means the following code is invalid
func remainder[T int | float64](a, b T) T {
return a % b // invalid operation: operator % not defined on a (variable of type T constrained by int | float64)
}
because %
is only valid for integer types.
But what if you really need to use a specific operator in a generic function like this? There is a way… It’s a bit awkward.
func remainder[T int | float64](a, b T) T {
switch t := any(a).(type) {
case int:
return any(t % any(b).(int)).(T)
default:
return 0
}
}
Quotes from The Go Programming Language Specification Version of August 2, 2023