updated on 2020-10-20
Expression = UnaryExpr | Expression binary_op Expression . UnaryExpr = PrimaryExpr | unary_op UnaryExpr . binary_op = "||" | "&&" | rel_op | add_op | mul_op . rel_op = "==" | "!=" | "<" | "<=" | ">" | ">=" . add_op = "+" | "-" | "|" | "^" . mul_op = "*" | "/" | "%" | "<<" | ">>" | "&" | "&^" . unary_op = "+" | "-" | "!" | "^" | "*" | "&" | "<-" .
https://golang.org/ref/spec#Operators
演算子 | 説明 | 利用例 |
+,- | 符号 | +100, -100 |
+ | 加算 | 1+2 |
- | 減算 | 1-1 |
/ | 割り算 | 4/2 |
* | 掛け算 | 3*5 |
% | 余り | 5%2 |
package main func main() { println(5 + 2) // 7 と表示されます println(5 - 2) // 3 と表示されます println(5 * 2) // 10 と表示されます println(5 / 2) // 2 と表示されます println(5 % 2) // 1 と表示されます
a := 5 b := 5
a++ b-- println(a) // 6 と表示されます println(b) // 4 と表示されます
}
演算子 | 説明 | 利用例 |
= | 変数への代入 | a = 100 |
:= | 変数の初期化と代入 | a := 100 |
+=,-= など | 演算と代入 | i += 2 |
++ | i += 1と同義 | i++ |
-- | i -= 1と同義 | i-- |
var number int
number = 100 // numberの値は100
number = 200 // numberの値は200
論理積: 二つの命題(PとQとおく)のいずれも真のときに真となり、それ以外のときは偽となる。(P\(\wedge\)Q)
論理回路や2進数の数値による論理積は、二つの入力の両方が1のときのみ出力が1となり、いずれか一方あるいは両方が0の場合は0となる。
論理和: 二つの命題(PとQとおく)のいずれか一方あるいは両方が真のときに真となり、いずれも偽のときに偽となるもの。(P\(\vee\)Q)
論理回路や2進数の数値による論理和は、二つの入力のいずか一方あるいは両方が1のとき出力が1となり、いずれも0の場合に0となる。
排他的論理和: 2つの入力のどちらか片方が真でもう片方が偽の時には結果が真となり、両方とも真あるいは両方とも偽の時は偽となる演算(論理演算)である。 XOR
否定: 論理回路や2進数の数値による論理和は、真を偽に、偽を真に反転させる。
演算子 | 説明 | 利用例 |
| | 論理和 | 0x10|0x01 |
& | 論理積 | 0x1&0xf |
^ | 否定 | ^0x3 |
^ | 排他的論理和 | 0xc^0x3 |
&^ | 論理積の否定 | 0xc&^0x3 |
<< | 左に算術シフト | 0x1<<4 |
>> | 右に算術シフト | 0x4>>1 |
package main import "fmt" func main() { a, b := 255, 85 // 2進数では、11111111, 01010101 // 論理積 fmt.Printf("%08b\n", a&b) // 01010101 // 論理和 fmt.Printf("%08b\n", a|b) // 11111111 //排他的論理和 fmt.Printf("%08b\n", a^b) // 10101010 // 論理積の否定 fmt.Printf("%08b\n", a&^b) // 10101010 //算術シフト c, d := 15, 240 // 00001111, 11110000 fmt.Printf("%08b\n", c<<4) // 11110000 fmt.Printf("%08b\n", d>>4) // 00001111 }
演算子 | 説明 | 利用例 |
|| | または | a || b |
&& | かつ | a && b |
! | 否定 | !a |
package main func main() { println(5 > 2 || 5 == 2 && 5 < 2) // true と表示されます println(true || false || false) // true と表示されます println(false || false || false) // false と表示されます
println(!(5 > 2)) // false と表示されます println(!(5 < 2)) // true と表示されます println(!(5 > 2 && 5 == 2 && 5 < 2)) // true と表示されます println(!(5 > 2 || 5 == 2 || 5 < 2)) // false と表示されます
}
演算子 | 説明 | 利用例 |
== | 等しいかどうか | a == b |
!= | 等しくないか | a != b |
< | aはbより小さい | a < b |
<= | aはb以下 | a <= b |
> | aはbより大きい | a > b |
>= | aはb以上 | a >= b |
演算子 | 説明 | 利用例 |
& | ポインタを取得 | &a |
* | ポインタが指す値を取得 | *a |
package main func main() { num := 100
// ポインター名前は、先頭に p を付けたり、最後に ptr を付ける場合が多い。ポインターの型は、ポインターが指し示すアドレスに入っている値の型の前に *(アスタリスク)付けて指定 var pnum *int = &num // pnum := &num という簡略定義もできます println(pnum) // 0xc000030780 などと16進数で表示される println(*pnum) // 100 と表示される *pnum = 200 println(pnum) // 0xc000030780 などと、上記と同じアドレスが表示される println(*pnum) // 200 と表示される }
変数の実体はメモリ上に格納された領域です。
「値渡し」と「参照渡し」とは、関数やメソッドにおける引数の渡し方の種類を表す用語です。説明すると、以下のようになります。
違う関数の間で、同じ変数の値を読み書きできたら便利です。その方法の一つとして、グローバル変数を使う方法があります。しかし、プログラミングではグローバル変数の使用は推奨されていません。プログラムの管理が難しくなるからです。そこで使われるのがポインターを使った参照渡しという方法です。
package main func main() { name := "名前は、main です" println(name) someFunc(&name) println(name) }
// ポインタの型には、アスタリスクをつけるのを忘れない、この場合は、関数の引数にはポインタが代入されるので、引数の型にはアスタリスクをつける func someFunc(name *string) { *name = "名前は、someFuncで書き換えられました" println(*name) }
(出力)
名前は、main です
名前は、someFuncで書き換えられました
名前は、someFuncで書き換えられました
値だけを渡してメモリは共有しないので、値を渡した関数でその値を変更しても、コピー元には変更が加わらない
package main
func main() {
name := "名前は、main です"
println(name)
someFunc(name)
println(name)
}
func someFunc(name string) {
name = "名前は、someFunc で書き換えられました"
println(name)
}
名前は、main です
名前は、someFunc で書き換えられました
名前は、main です
goroutineとchannelの2つを理解する必要がある
goroutine (ゴルーチン): Go ランタイムによって管理される並行処理を扱うためのコルーチン。 普通のコルーチンとは違って処理の割り込みや再開を開発者がプログラム上から制御することはできない。
ゴルーチンはM:Nモデルと呼ばれる複数(N)のカーネルスレッドに 複数(M)のユーザスレッドを対応させたものにスケジューリングされるため、 複数のCPUコアを扱うことができる。
channel (チャネル): 並行実行(同時に実行)されるgoroutine間を接続するパイプ(トンネル)であり、あるゴルーチンがチャネルへ値を送信し、別のゴルーチンがチャネル値を受け取るのに使用する
演算子 | 説明 | 利用例 |
<- | チャネルへの送受信 | ch<-100, <-ch |
func main() { c1 := make(chan string) c2 := make(chan string) go func() { time.Sleep(2 * time.Second) c2 <- "two" }() go func() { time.Sleep(1 * time.Second) c1 <- "one" }() for i := 0; i < 2; i++ { select { case msg1 := <-c1: // チャネル1から送信完了した場合 fmt.Println("received", msg1) case msg2 := <-c2: // チャネル2から送信完了した場合 fmt.Println("received", msg2) } } }
(出力)
received one
received two