Operator operations are the operations using all kinds of operators. This article will introduce common operators in Go. More operators will be introduced in other articles later.
This article will only introduce arithmetic operators, bitwise operators, comparison operators, boolean operators and string concatenation operator. These operators are either binary operators or unary operators. A binary operator operation takes two operands and a unary operator operation takes only one operand.
All the operator operations introduced in this articles each returns one result.
This article doesn't pursue the accuracy of some descriptions. For example, when it says that a binary operator requires the types of its two operands must be the same, what it means is:
Similarly, when it says an operator, either a binary operator or a unary operator, requires the type of one of its operands must be of a certain type, what it means is:
Before introducing all kinds of operators, we should know what are constant expressions and a fact in the evaluations of constant expressions. Expressions will get explained in a later article expressions and statements. At present, we just should know that most of the operations mentioned the current article are expressions.
If all the operands involved in an expression are constants, then this expression is called a constant expression. All constant expressions are evaluated at compile time. The evaluation result of a constant expression is still a constant.
Only if one operand in an expression is not a constant, the expression is called a nonconstant expression.
Go supports five basic binary arithmetic operators:
Operator  Name  Requirements For The Two Operands 

+  addition  The two operands must be both values of the same basic numeric type. 
  subtraction  
*  multiplication  
/  division  
%  remainder  The two operands must be both values of the same basic integer type. 
The five operators are also often called sum, difference, product, quotient and modulo operators, respectively. Go 101 will not explain how these operator operations work in detail.
Go supports six bitwise binary arithmetic operators:
Operator  Name  Requirements For The Two Operands And Mechanism Explanations 

&  bitwise and 
The two operands must be both values of the same integer type. Mechanism explanations (a value with the subscript2 is the binary literal form of the value):

  bitwise or  
^  bitwise xor  
&^  bitwise clear  
<<  bitwise left shift 
The left operand must be an integer
and the right operand must be an unsigned integer
(or an untyped
integer constant which is representable as an
If the left operand of a bitwiserightshift operation
is (or is viewed as) a signed integer,
then the sign bit (the highest bit) in the left operand
will be always kept in the result value. For example. if the
left operand is an 
>>  bitwise right shift 
^{(1)} Since Go the coming 1.13, it is possible that the requirements of the right operand in a bitwise shift operation will be relaxed to any integers, either unsigned or signed.
Go also supports three unary arithmetic operators:
Operator  Name  Explanations 

+  positive 
+n is equivalent to 0 + n .

  negative 
n is equivalent to 0  n .

^ 
bitwise complement (bitwise not) 
^n is equivalent to m ^ n ,
where m is a value all of which bits are 1.
For example,
if the type of n is int8 ,
then m is 1 ,
and if the type of n is uint8 ,
then m is 0xFF .

~
.
+
can also be used as string concatenation operator,
which will be introduced below.
*
can also be used as pointer dereference operator,
and the bitwiseand operator &
can also be used as pointer address operator.
Please read pointers in Go for details later.
>>>
doesn't exist in Go.
Pow
function
in the math
standard package instead.
Code package and package import will be introduced in the next article
packages and imports.
&^
is a unique operator in Go.
m &^ n
is equivalent to m & (^n)
.
Example:
func main() {
var (
a, b float32 = 12.0, 3.14
c, d int16 = 15, 6
e uint8 = 7
)
// The ones compile okay.
_ = 12 + 'A' // two untyped operands (both are numeric)
_ = 12  a // one untyped operand and one typed operand
_ = a * b // two typed operands
_ = c % d
_, _ = c + int16(e), uint8(c) + e
_, _, _, _ = a / b, c / d, 100 / 9, 1.23 / 1.2
_, _, _, _ = c  d, c & d, c ^ d, c &^ d
_, _, _, _ = d << e, 123 >> e, e >> 3, 0xF << 0
_, _, _, _ = b, +c, ^e, ^1
// The following ones fail to compile.
_ = a % b // error: a and b are not integers
_ = a  b // error: a and b are not integers
_ = c + e // error: type mismatching
_ = b >> 5 // error: b is not an integer
_ = c >> 5 // error: 5 is not representable as uint
_ = e << c // error: c is not an unsigned integer
}
int
,
rune
, float64
, complex128
.
For example, if the default type of one untyped operand is int
,
and the other one is rune
, then the default type of
the result untyped value is rune
.
int
.
For such cases, the result is also an untyped value and
the default type of the result is the same as the left operand.
func main() {
const X, Y, Z = 2, 'A', 3i // three untyped values.
// Default types: int, rune, complex64.
var a, b int = X, Y // two typed values.
d := X + Y // the type of d is the default type of Y: rune (int32).
e := Y  a // the type of e is the type of a: int.
f := a * b // the type of f is the types of a and b: int.
g := Z * Y // the type of g is the default type of Z: complex64.
println(X, Y, Z) // 2 65 (+0.000000e+000+3.000000e+000i)
println(d, e, f, g) // 67 63 130 (+0.000000e+000+1.950000e+002i)
}
Another example (bitwise shift operations):
const N = 2
const A = 3.0 << N // A == 6, its default type is int.
const B = int8(3.0) << N // B == 6, it is typed and its type is int8.
var m = uint(32)
// The following three lines are equivalent to each other.
var x int64 = 1 << m // the type of 1 is deduced as int64, not int.
var y = int64(1 << m) // the type of 1 is deduced as int64, not int.
var z = int64(1) << m
// The following two lines fail to compile.
/*
var _ = 1.23 << m // error: shift of type float64
const _ = 1 << B // error: the right operand must be unsigned.
*/
The last rule for bitwise shift operator operation is to avoid some operations
returning different results on different architectures.
For example, the bitwise operation at line 8 (or line 7) will
return different results between 32bit architectures and 64bit architectures
if the operand 1
is deduced as
int
instead of int64
,
which may produce some bugs hard to detect.
const n = uint(2)
var m = uint(2)
// The following two lines compile okay.
var _ float64 = 1 << n
var _ = float64(1 << n)
// The following two lines fail to compile.
var _ float64 = 1 << m
var _ = float64(1 << m)
The reason of the last two lines failing to compile is they are both
equivalent to the followings two line:
var _ = float64(1) << m
var _ = 1.0 << m // error: shift of type float64
Overflows are not allowed for typed constant values but are allowed for nonconstant and untyped constant values, either the values are intermediate or final results. Overflows will be truncated (or wrapped around) for nonconstant values, but overflows (for default types) on untyped constant value will not be truncated (or wrapped around).
Example:// Results are nonconstants.
var a, b uint8 = 255, 1
var c = a + b // okay: higher overflowed bits are truncated. c == 0
var d = a << b // okay: higher overflowed bits are truncated. d == 254
// Results are untyped constants.
const X = 0x1FFFFFFFF * 0x1FFFFFFFF // okay, though X overflows int.
const R = 'a' + 0x7FFFFFFF // okay, though R overflows rune.
// Operation results or conversion results are typed values.
// These lines all fail to compile.
var e = X // error: untyped constant X overflows int.
var h = R // error: constant 2147483744 overflows rune.
const Y = 128  int8(1) // error: 128 overflows int8
const Z = uint8(255) + 1 // error: the result 256 overflow uint8.
Assume x
and y
are two operands of the same integer type,
the integer quotient q
(= x / y
)
and remainder r
(= x % y
)
satisfy x == q*y + r
, where r < y
.
If r
is not zero, its sign is the same as x
(the dividend).
The result of x / y
is truncated towards zero.
If the divisor y
is a constant, it must not be zero.
If the divisor is zero at run time and it is an integer,
a runtime panic occurs.
Panics are like exceptions in some other languages.
We can learn more about panics in this article.
println( 5/3, 5%3) // 1 2
println( 5/3, 5%3) // 1 2
println(5/3, 5%3) // 1 2
println(5/3, 5%3) // 1 2
println(5.0 / 3.0) // 1.666667
println((11i)/(1+1i)) // 1i
var a, b = 1.0, 0.0
println(a/b, b/b) // +Inf NaN
_ = int(a)/int(b) // compile okay but panic at run time.
// The following two lines fail to compile.
println(1.0/0.0) // error: division by zero
println(0.0/0.0) // error: division by zero
op=
For Binary Arithmetic Operators
For a binary arithmetic operator op
, x = x op y
can be shortened to x op= y
.
In the short form, x
will be only evaluated once.
var a, b int8 = 3, 5
a += b
println(a) // 8
a *= a
println(a) // 64
a /= b
println(a) // 12
a %= b
println(a) // 2
b <<= uint(a)
println(b) // 20
++
And Decrement 
Operators
Like many other popular languages, Go also supports
the increment ++
and decrement 
operators.
However, operations using the two operators don't return any results,
so such operations can not be used as
expressions.
The only operand involved in such an operation must be a numeric value,
the numeric value must not be a constant, and the ++
or

operator must follow the operand.
package main
func main() {
a, b, c := 12, 1.2, 1+2i
a++ // okay
b // okay
c++ // okay
// The following lines fail to compile.
/*
_ = a++
_ = b
_ = c++
++a
b
++c
*/
}
Operator  Name  Requirements For The Two Operands 

+  string concatenation  The two operands must be both values of the same string type. 
The op=
form also applies for the string concatenation operator.
println("Go" + "lang") // Golang
var a = "Go"
a += "lang"
println(a) // Golang
If one of the two operands of a string concatenation operation is a typed string, then the type of the result string is the same as the type of the typed string. If both the of the two operands are untyped (constant) strings, the result is also an untyped string value.
Go supports two boolean binary operators and one boolean unary operator:
Operator  Name  Requirements For Operand(s) 

&&  boolean and (binary)  The two operands must be both values of the same boolean type. 
  boolean or (binary)  
!  boolean not (unary)  The type of the only operand must be a boolean type. 
We can use the !=
operator introduced in the next subsection as the boolean xor operator.
// x y x && y x  y !x !y
true true true true false false
true false false true false true
false true false true true false
false false false false true true
If one of the two operands is a typed boolean, then the type of the result boolean is the same as the type of the typed boolean. If both the of the two operands are untyped booleans, the result is also an untyped boolean value.
Go supports six comparison binary operators:
Operator  Name  Requirements For The Two Operands 

==  equal to  Generally, the types of its two operands must be the same. For detailed rules, please read comparison rules in Go. 
!=  not equal to  
<  less than  The two operands must be both values of the same integer type, floatingpoint type or string type. 
<=  less than or equal to  
>  larger than  
>=  larger than or equal to 
The type of the result of any comparison operation is always an untyped boolean value. If both of the two operands of a comparison operation are constant, the result is also a constant (boolean) value.
Later, if we say two values are comparable, we mean they can be compared
with the ==
and !=
operators.
We will learn that values of which types are not comparable later.
Values of basic types are all comparable.
Please note that, not all real numbers can be accurately represented in memory, so comparing two floatingpoint (or complex) values may be not reliable. We should check whether or not the absolution of the difference of two floatingpoint values is smaller than a small threshold to judge whether or not the two floatingpoint values are equal.
The following is the operator precedence in Go.
Top ones have higher precedence.
The operators in the same line have the same precedence.
Like many other languages, ()
can be used to promote precedence.
* / % << >> & &^
+   ^
== != < <= > >=
&&

One obvious difference to some other popular languages
is that the precedence of <<
and
>>
is higher than +
and 
in Go.
2.2
instead of 2.7
.
The reason is the precedence of the division operation is higher than
the addition operation, and in the division operation,
both 3
and 2
are viewed as integers.
The evaluation result of 3/2
is 1
.
var x = 1.2 + 3/2
The two named constants declared in the following program are not equal. In the first declaration, both
3
and 2
are
viewed as integers, however, they are both viewed as floatingpoint numbers
in the second declaration.
package main
const x = 3/2*0.1
const y = 0.1*3/2
func main() {
println(x) // +1.000000e001
println(y) // +1.500000e001
}
Same as C/C++,
there are two pointer related operators, *
and &
.
Yes the same operator symbols as the multiplication and bitwiseand operators.
&
is used to take the address of an addressable value,
and *
is used to dereference a pointer value.
Unlike C/C++, in Go, values of pointer types don't support arithmetic operations.
For more details, please read pointers in Go later.
There are some other operators in Go. They will be introduced and explained in other Go 101 articles.
The Go 101 project is hosted on both Github and Gitlab. Welcome to improve Go 101 articles by submitting corrections for all kinds of mistakes, such as typos, grammar errors, wording inaccuracies, description flaws, code bugs and broken links.
Support Go 101 by playing Tapir's games.