Go言語とは
なんだか並列処理とかが簡単に実装できるという噂。
正直、まだよくわかりません!
公式のチュートリアルをやっていき、引っかかるところを自分のメモがてら、つらつら書いていきます。
基本的な定義の記述
パッケージの定義
C++でいうヘッダーをGoではパッケージと呼ぶ。
書き方は以下のように、それぞれのファイルの最初に記述する。
他パッケージの読み込みはimportの中で行う。
package main
import (
"fmt"
"math/rand"
)
func main() {
// 他パッケージを読み込む際は最後のパッケージ名だけでよい
// この場合は"math/rand"ではなく"rand"だけでオッケー。
fmt.Println("My favorite number is", rand.Intn(10))
}
C++でいうmain文はgoでいうmainパッケージにあたり、プログラムはmainパッケージから実行される。
関数の定義
他の言語と異なり、引数は変数名の後ろに記述する。
同じ型の変数が続く場合は省略もできる。例えば、x int, y intをx, y intのように。
package main
import "fmt"
func add(x, y int) int {
return x + y
}
func main() {
// sum = add(1, 4)だと"undefined: sum"ってエラーを吐く
// ちゃんと書くならvar sum = add(1, 4)
sum := add(1, 4)
fmt.Println(sum)
}
また、戻り値を最初に宣言して処理を行う書き方もある。
このとき、returnにはなにも書かない。
package main
import "fmt"
func add_each(input int) (output1, output2 int) {
output1 = input + 1
output2 = input + 2
return
}
func main() {
fmt.Println(add_each(17))
}
// 18, 19を出力
関数の引数を関数にする(ちょい応用)
自分はすぐに理解できなかったので別項目として記載します。
go言語では関数の引数に関数を入れることができる。
package main
import (
"fmt"
)
func compute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
func main() {
plus := func(x, y float64) float64 {
fmt.Println("x:", x, ",y:", y)
return x + y
}
fmt.Println(plus(5, 12))
fmt.Println("==========")
compute(plus)
fmt.Println("==========")
fmt.Println(compute(plus))
}
/* 実行結果
x: 5 ,y: 12
17
==========
x: 3 ,y: 4
==========
x: 3 ,y: 4
7
*/
慣れてないとよく分からないんですが
func compute(fn func(float64, float64) float64) float64{return fn(3, 4)}が、
float64の引数が2つの関数だったら、どんな関数でも実行できるようなcomputeっていう関数を定義
と脳内変換すれば理解できるんですかね?
自分はそう考えています。
変数の定義
変数の定義はvarと記述することで定義できる。
省略の記述が多いので以下にまとめる。
- 初期値を代入する場合、型の宣言を省略できる。
- 関数の中であれば
:=演算子でvar宣言を省略できる。 - 初期値を省略した場合、型に応じて
0、""、false等が代入される。
package main
import "fmt"
var i, j int = 1, 2
var c, python, java = true, false, "no!"
func main() {
k := 3
var zero int
fmt.Println(i, j, k, c, python, java, zero)
}
// 1 2 3 true false no! 0 を出力
定数の定義
constで宣言できる。
:=演算子は使うことができない。
基本的な変数に対する処理
変数の型変換
型変換は型名()だけで行うことができる。
var i int = 42
var f float64 = float64(i)
var u uint = uint(f)
// よりシンプルな記述
i := 42
f := float64(i)
u := uint(f)
型の確認
fmtのPrintf関数による方法をここでは紹介する。
cのprintf関数と似ていて%なにかで変数を文字列に埋め込んで出力することができる。
変数の型は%T、変数の値は全て%vで表せる。
var f float64 = 1
fmt.Printf("(%v, %T)\n", f, f) // (1, float64)を返す
Printfでは他にもクラスの中身の確認や関数の引数も調べることができる。
詳しくは、@rock619さんの記事にまとまっているのでそちらを参照。
「fmt.Printfなんかこわくない」
https://qiita.com/rock619/items/14eb2b32f189514b5c3c#x-3
イテレータや条件分岐
for文
for文の条件式の()が不要。
また初期化、後処理を省略することもできる。
package main
import "fmt"
func main() {
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
fmt.Println(sum)
// 省略形(これはもうwhile文と一緒)
n := 1
for ; n < 1000; {
n += n
}
fmt.Println(n)
// さらに省略形
m := 1
for m < 1000 {
m += m
}
fmt.Println(m)
}
go言語にwhile文等は存在せず、イテレータはfor文のみ。
無限ループはfor文の条件さえも省略してfor{}と記述する。
if文
for文と同じく()を省略して書く。
package main
import (
"fmt"
"math"
)
func sqrt(x float64) string {
if x < 0 {
return sqrt(-x) + "i"
}
return fmt.Sprint(math.Sqrt(x))
}
func main() {
fmt.Println(sqrt(2), sqrt(-4))
}
また、for文と同じように初期値の代入を記述することも可能。
package main
import (
"fmt"
)
func half(x int) bool {
if x % 2 == 0 {
return true
} else {
return false
}
}
func main() {
number := 5
// vを初期値としてif文で評価
if v:= half(number); v==true {
fmt.Println("偶数")
} else {
fmt.Println("奇数")
}
}
swich文
上から下にcaseの値を評価していき、条件が一致すればbreakする。
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("When's Saturday?")
today := time.Now().Weekday()
switch time.Saturday {
case today + 0:
fmt.Println("Today.")
case today + 1:
fmt.Println("Tomorrow.")
case today + 2:
fmt.Println("In two days.")
default:
fmt.Println("Too far away.")
}
}
defer文(実行遅延を行うもの)
デストラクタのように処理の最後に実行させるためのもの。
例えば以下のコードの場合、helloが先に出力され、最後にworldが出力される。
package main
import "fmt"
func main() {
defer fmt.Println("world")
fmt.Println("hello")
}
ポインタとか
ポインタ
Cのポインタと一緒。なにも初期値を与えないとnilを返す。
&演算子でポインタの示すアドレスを指定。
*演算子でポインタの指す値を取得。
var p *int // ポインタの定義
i := 42
p = &i
fmt.Println(*p) // 42を返す
fmt.Println(p) // アドレス0x414020を返す
構造体
これもCと似通っている。ドットでアクセスする。
ポインタからメンバ変数Xにアクセスするときは下記のように省略して書ける。
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
fmt.Println(v) // {1 2}を出力
v.X = 4
fmt.Println(v.X) // 4を出力
p : = &v
p.X = 5 // (*p).Xと書かなくてよい
fmt.Println(v.X) // 5を出力
}