Arithmetic operators

January 29, 2024

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 addition s += x * y are computed with float32 or float64 precision, respectively, depending on the type argument for F.

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


Share this

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

Unsure? Browse the archive .