オペランドと演算子
オペランドは演算の対象となる値や式であり、演算子はそれらを結びつける記号です。演算子はオペランドの数に応じて二項演算子と単項演算子に分かれます。
二項演算子
二項演算子は2つのオペランドの間に置きます。
| 種類 | 演算子 |
|---|---|
| 算術 | + - * / % |
| ビット | & | ^ &^ << >> |
| 比較 | == != < <= > >= |
| 論理 | && || |
a, b := 1, 2
sum := a + b // 3
masked := a & b // 0
ok := a < b // true
both := true && ok // true単項演算子
単項演算子はオペランドの直前に置きます。Go言語では前置のみをサポートしています。
| 演算子 | 意味 |
|---|---|
+ | 値はそのまま |
- | 正負の反転 |
! | 真偽値の反転 |
^ | ビットの反転 |
* | ポインタが指す値の参照 |
& | アドレスの取得 |
<- | チャネルからの値の受信 |
pos := +10 // 10
neg := -10 // -10
on := true
stopped := !on // false
flipped := ^uint8(0b00001100) // 0b11110011
var n int = 10
p := &n
v := *p // 10
ch := make(chan int, 1)
ch <- 1
got := <-ch // 1算術演算子
| 演算子 | 意味 | 対象 |
|---|---|---|
+ | 加算、文字列の連結 | 整数、浮動小数点、複素数、文字列 |
- | 減算 | 整数、浮動小数点、複素数 |
* | 乗算 | 整数、浮動小数点、複素数 |
/ | 除算。整数除算はゼロ方向へ切り捨て | 整数、浮動小数点、複素数 |
% | 剰余 | 整数 |
& | ビット積 | 整数 |
| | ビット和 | 整数 |
^ | 排他的論理和 | 整数 |
&^ | 指定ビットの消去。右辺で1のビット位置を0にする | 整数 |
<< | 左シフト。右オペランドは0以上 | 整数 |
>> | 右シフト。右オペランドは0以上 | 整数 |
a, b := 10, 3
sum := a + b // 13
joined := "go" + "lang" // "golang"
diff := a - b // 7
prod := a * b // 30
quot := a / b // 3
negQuot := (-10) / 3 // -3
rem := a % b // 1
x, y := uint8(0b1100), uint8(0b1010)
bitAnd := x & y // 8
bitOr := x | y // 14
bitXor := x ^ y // 6
bitClear := x &^ y // 4
shiftLeft := x << 1 // 24
shiftRight := x >> 1 // 6比較演算子
| 演算子 | 意味 | 対象 |
|---|---|---|
== | 等しい | 比較可能な型 |
!= | 等しくない | 比較可能な型 |
< | より小さい | 順序付け可能な型 |
<= | 以下 | 順序付け可能な型 |
> | より大きい | 順序付け可能な型 |
>= | 以上 | 順序付け可能な型 |
順序付け可能な型は整数、浮動小数点、文字列です。boolやポインタは等値比較はできても順序比較はできません。
スライス、マップ、関数は値同士を比較できませんが、いずれもnilとの等値比較は可能です。配列は要素型が比較可能であれば==で比較できます。
x, y := 1, 2
isLess := x < y // true
isLessOrEqual := x <= y // true
isGreater := x > y // false
isGreaterOrEqual := x >= y // false
isEqual := x == y // false
isNotEqual := x != y // true
// []int{1} == []int{1} // コンパイルエラー: スライス同士は比較不可
// map[int]int{1: 1} == map[int]int{1: 1} // コンパイルエラー: マップ同士は比較不可
// func() {} == func() {} // コンパイルエラー: 関数同士は比較不可
var pending []int
isNil := pending == nil // true: スライス、マップ、関数はnilと比較可能論理演算子
| 演算子 | 意味 |
|---|---|
&& | 論理積 |
|| | 論理和 |
! | 論理否定 |
&&と||は短絡評価します。&&は左辺がfalseなら右辺を評価しません。||は左辺がtrueなら右辺を評価しません。右辺に関数呼び出しなどの副作用がある場合でも、評価されない限り実行されません。
func sideEffect(n int) int { return n }
active := true
paused := !active // false
if false && sideEffect(2) == 2 {
// 左辺がfalseのためsideEffectは評価されない
}
if true || sideEffect(2) == 2 {
// 左辺がtrueのためsideEffectは評価されない
}++と--
| 演算子 | 意味 |
|---|---|
++ | 1増やす |
-- | 1減らす |
文であり、式としては扱えません。前置の++iはなく、f(i++)のように式のオペランドに含めることもできません。
i := 0
i++
i--
// f(i++) // コンパイルエラー: 文のため式の中では使えない型変換
二項演算子のオペランドは、シフト演算と非型付き定数を除き同一の型でなければなりません。型付きの変数同士に暗黙の数値変換はないため、intとfloat64をそのまま計算するとコンパイルエラーになります。一方のオペランドが非型付き定数なら、相手の型で表現できる値であればその型として使えます。
var x int = 1
var y float64 = 2
// z := x + y // コンパイルエラー: 型の異なる変数同士は演算不可
mixed := float64(x) + y
sum := x + 2 // 非型付き定数2はintとして扱われるifやforの条件式と論理演算子のオペランドは真偽値に限ります。boolのほか、基底型がboolの型も使えます。数値や文字列からboolへの暗黙変換はなく、bool(n)のような明示的な変換もありません。真偽判定には比較式を用います。
n := 1
s := "go"
var err error
// if n { } // コンパイルエラー: 条件式は真偽値が必要
// if s { } // コンパイルエラー
// ok := bool(n) // コンパイルエラー: intからboolへの変換は不可
hasN := n != 0 // true
hasS := s != "" // true
hasErr := err != nil // false定数式
定数式は定数のみで構成され、コンパイル時に計算されます。計算結果は定数の宣言や配列の要素数指定などにそのまま利用できます。
const size = 1 + 2*3
var arr [size]int演算子の優先順位
二項演算子
仕様では優先度1から5まで定義されており、数値が大きいほど強く結合し、先に計算されます。
| 優先度 | 演算子 |
|---|---|
| 5 | * / % << >> & &^ |
| 4 | + - | ^ |
| 3 | == != < <= > >= |
| 2 | && |
| 1 | || |
同じ優先度の二項演算子は左から右へ結合します。たとえば42 + a - bは(42 + a) - bと解釈されます。
n := 1 + 2*3 // 乗算が優先され7になる単項演算子
単項演算子は、すべての二項演算子よりも強く結合します。++と--は文であるため優先順位の定義には含まれません。
x := uint8(0b1100)
n := ^x >> 1 // 単項演算の^xが優先されるため121評価順序
関数呼び出し、メソッド呼び出し、チャネル受信、二項論理演算は、記述された順序に従って左から右へ評価されます。たとえばf() + g()ではf()が先に実行されてからg()が実行されます。関数の引数同士も同様で、sub(next(), next())では左側のnext()が先に呼び出されます。
一方、変数の参照と関数呼び出しの相対的な評価順序は仕様で定められていません。
func f() int { return 1 }
func g() int { return 2 }
sum := f() + g() // f()の実行後にg()が実行され3になる
var seq int
func next() int {
seq++
return seq
}
func sub(a, b int) int { return a - b }
sub(next(), next()) // 左辺が1、右辺が2となり常に-1
n := 1
inc := func() int { n++; return n }
pair := []int{n, inc()} // nの参照とinc()の実行順序が未規定のため[1, 2]または[2, 2]