#注意
更新型の記事です。
筆者の学習に合わせて更新されていきます。
Goのインストール
Golangより、ファイルをダウンロードし、手順に従いインストール
(mac, windows, linux全てに対応)
Goを始める
(Mac)
ターミナルで、絶対パスを利用し
cd /usr/local/go
へ移動、goディレクトリで
go version
と入力し、goのバージョンを確認できたら、インストールが完了している。
実際のコード
公式チュートリアルを参照
https://golang.org/doc/tutorial/getting-started
- ホームディレクトリに移動し
mkdir hello
と入力し、helloディレクトリを作成し、
cd hello
で、helloディレクトリへ移動
2.利用しているテキストエディター(vscodeやvimなど、ほとんどのテキストエディターに対応しているらしい)で、hello.goファイルを作成し、以下のコードを入力
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
- package main: パッケージは機能の塊の単位。mainパッケージを宣言している。
- import "fmt": テキストをコンソールに出力する機能を持った、テキスト生成のためのパッケージをインポート
- func main(): コンソールに出力するための処理を記述
fmtパッケージに定義されたPrintf関数をコールします。
なお、importが二つ以上になった場合は
import (
"errors"
"fmt"
)
という風に、まとめる事ができる。
変数定義
//これが一番省略形
message := fmt.Sprintf("Hi, %v. Welcome!", name)
//varで変数を定義、型を明記
var message string
message = fmt.Sprintf("Hi, %v. Welcome!", name)
一番省略形を用いた変数宣言は、自動で型を付与し、変数定義を行ってくれる。超すごい。
ただし...
これらは関数の内部でしか使用できません。
とのこと。
※なお、一度定義しているにもかかわらず利用していない変数があると、エラーが起きるので注意
変数に値を代入・その値の更新
message = "Taro"
= は変数の代入・更新
:= は変数の定義
ロジック系
##配列
array
var fruits [3]string
fruits[0] = "apple"
fruits[1] = "orange"
fruits[2] = "strawberry"
fmt.Println(fruits)
//→[apple orange strawberry]
primes := [6]int{2, 3, 5, 7, 11, 13}
fmt.Println(primes)
//→[2 3 5 7 11 13]
配列は、固定調とされている(?)
####slice
package main
import "fmt"
func main() {
primes := [6]int{2, 3, 5, 7, 11, 13} //array
var s []int = primes[1:4] //slice, [ここから:ここまで]=[primesの1~3まで]
fmt.Println(s)
//→[3 5 7]
}
sliceはなの通り、範囲を指定して(スライスして)新たな配列を生成します。
新しい配列を作る事ができるに加えて、元の配列を操作することも可能です。
package main
import "fmt"
func main() {
names := [4]string{
"Saito",
"Tanaka",
"Yamada",
"Fuji",
}
fmt.Println(names)
//→[Saito Tanaka Yamada Fuji]
a := names[0:2]
b := names[1:3]
fmt.Println(a, b)
//→[Saito Tanaka] (0:2は、「2より下」を表す)
// [Tanaka Yamada](1:3は、「1以上3より下」を表す)
b[0] = "XXX" //b[0]にXXXを代入
fmt.Println(a, b)
fmt.Println(names)
//→[Saito XXX]
// [XXX yamada]
//→[Saito XXX Yamada Fuji]
}
以上から、sliceで取得した配列の値を変えると、元の配列であるnameの値を変える事ができる事がわかります。つまり、この記事で説明されている「参照渡し」が、成立していると言えるでしょう。
####slice defaults
a[0:10]
a[:10]
a[0:]
a[:]
以上のsliceの表現は、すべて同じ意味を表します。意味は
**「aの配列0番目から9番目(10より小さい番号)を取得し新たな配列を作成する」**です。
この事からsliceの範囲指定のデフォルト値について、3つのことがわかります。
- 明示しない場合、最小値は0
- 明示しない場合、最大値は元の配列の最後の値
- 範囲を明示しない場合は、元の配の最初から最後まで
これは、A Tour of Goで、slice defaultというタイトルで紹介されています。
####sliceの長さと容量
長さは、配列にある実際の値の個数
容量は、その配列に値がいくつ入るかを示した値
結論、最小値の方をぶった切ると容量(cap)が減ります。
最大値からぶった切ると、長さ(len)だけ減ります。
package main
import "fmt"
func main() {
n := []int{1, 3, 6, 10, 15}
printSlice(n)
// 長さを0にします。
n = s[:0]
printSlice(n)
// 長さを4にします。
n = s[:4]
printSlice(n)
// 容量を二つ減らします。
n = s[2:]
printSlice(n)
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(n), cap(n), n)
//len(n)はsliceした後の、cap(n)はsの容量、nは元々の配列です。
//→len=5 cap=5 [1, 3, 6, 10, 15]
// len=0 cap=5 []
// len=4 cap=6 [1, 3, 6, 10]
// len=2 cap=4 [6, 10] //ここで、容量を減らしています。
}
ちなみに、%vはその変数や配列に指定されているデフォルトの値を返すものみたいです。
(参照:Go言語 - %Tや%vの書式で出力される文字列)
####append
sliceに新しい値を追加するときに用いる
package main
import "fmt"
func main() {
var s []int
printSlice(s) //→len=0 cap=0 []
// 0を追加します。
s = append(s, 0)
printSlice(s) //len=1 cap=1 [0]
// 必要に応じて、sの容量も増えていきます。
s = append(s, 1)
printSlice(s) //len=2 cap=2 [0 1]
// 一つ以上の値を一度に追加することもできます。
s = append(s, 2, 3, 4, 5, 6, 7)
printSlice(s) //len=8 cap=8 [0 1 2 3 4 5 6 7]
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
make
goにおける配列は、上記で挙げたように2種類あります。
arrayは、一度指定したら変更することができません。これを、固定調と言います。
対してsliceは、arrayの値を値を変えたり、元々のarrayの長さや要領も変えることができました。これを、可変調と言います。
ここで気付いた人もいるかもしれませんが、sliceを元の配列なしに作成することができるのではないかと疑問に思いました。つまり、sliceそのものを最初から作成するためにはどうすればいいのでしょうか。
結論、makeを使います。
package main
import "fmt"
func main() {
a := make([]int, 5) //make([]int, 5)でsliceを作っています。今回のsliceは、値はすべて0, 長さ/容量が5というsliceです。
printSlice("a", a)
//→a len=5 cap=5 [0 0 0 0 0]
b := make([]int, 0, 5)
printSlice("b", b)
//→b len=0 cap=5 []
}
func printSlice(s string, x []int) {
fmt.Printf("%s len=%d cap=%d %v\n",
s, len(x), cap(x), x)
}
という感じでsliceを作成することができました。
##条件分岐
####条件分岐(if)
if 条件式 {
条件式がtrueだった時の処理
} else {
条件式がfalseだった時の処理
}
条件分岐(if/if else)
if 条件式 {
ifの条件式がtrueだった時の処理
} else if 条件式 {
else ifの条件式がtrueだった時の処理
}
####条件分岐 (switch)
n = 2
switch n{
case A:
処理
case B:
処理
case C:
処理
default:
処理
この記述は、**「nがA/B/C/それ以外の時、処理を行う」**という意味。
nの存在が必要ない場合は、省略も可能
##繰り返し
for i := 1; i <= 14, i += 1 {
処理
}
一つづつ解説すると
for i := 1;
で、変数iを定義し、初期値(繰り返しのスタートの値)とする
i <= 14
どの範囲まで(今回は、iが14になるまで)を定義
i += 1
どのくらいのスピードで(この場合は、iが1ずつ増加する)
####range
forの繰り返し機能を、sliceやmapの値に適応させます。(Rubyのeachメソッドに限りなく近いと思います。)
package main
import "fmt"
var nums = []int{1, 2, 4, 8, 16, 32, 64, 128}
func main() {
for i, v := range nums {
fmt.Printf("2**%d = %d\n", i, v)
}
}
rangeは、二つの引数を持ちます。何番目か?を示すindexと、その番目の値は何か?を示すvalueの2点です。
今回は、iに「何番目か」, vに「その番目の値は何か?」を代入する形です。
また、もしindexかvalueのどちらかが必要ない時は
package main
import "fmt"
var nums = []int{1, 2, 4, 8, 16, 32, 64, 128}
func main() {
for _, v := range nums { //iを_(アンダーバー)に変更すると、indexは処理用の値として渡されなくなります。
fmt.Printf("%d\n", v) //value(値)だけが繰り返されます。
}
for i := range nums {
fmt.Printf("%d\n", i) //indexだけが繰り返されます。
}
}
map
map ≒ rubyのハッシュ(キーバリューストア)のようなもの
messages := make(map[string]string)
//[key]valueの順番で、それぞれ指定する。
とする事で、キーとバリューの型を指定する。
##mapの値をいじる
package main
import "fmt"
func main() {
s := make(map[string]int) //sに初期化した状態で代入
s["English_points"] = 89 //89をEnglish_pointsに代入
fmt.Println("Score", s["English_points"]) //→89
s["Enlish_points"] = 59 //59をEnglish_pointsに再代入
fmt.Println("Score", s["English_points"]) //→59
delete(m, "English_points") //mのEnglish_Scoreキーを削除
fmt.Println("Score", s["English_point"]) //→0
v, ok := m["English_points"] //vで値、okでキーが存在するかの結果をそれぞれ代入
fmt.Println("Score", v, "Present?", ok) //→Score 0 Present? false(English_pointsキーは削除されているから、falseが返される。)
}
関数
処理のまとまりのこと。
import "fmt"
func main() {
question()
}
func question() {
fmt.Println("質問を入力してください")
fmt.Scan(&text)
fmt.Printf("質問内容は%sですね", text)
}
今回、関数は二つ
- main(questionを呼び出し)
- question(質問を入力してもらい、それを確認する処理を担当)
このように、関数を別の関数内で呼び出す事ができる。
引数と戻り値
import "fmt"
func main() {
question(1, "なぜ空は青いのですか?")
}
func question(number int, text string) string {
fmt.Println("Q%d: あなたの質問は%sですね", number, text)
fmt.Scan(&text)
fmt.Printf("%s", text)
return "実は青く見えているだけなんだよ。"
}
さて、一つずつ解説を
まず、main関数の方で、実引数を伴わせながらask関数を呼び出します。
func main() {
question(1, "なぜ空は青いのですか?")
}
今回は、1と”なぜ空は青いのですか?”という文章をask関数へ引数として渡しています。それぞれ、int型、string型ですね。そこで、受け取る側のask関数でも受け取る用意をします。
func question(number int, text string)
このようにquestionのカッコの中にint型のnumberと、string型のtextを仮引数として定義しました。
その仮引数を用いて、question関数内の処理を行います。
そして、その関数の最後の値(処理された結果の値)を、戻り値と言います。戻り値は今回は処理に関係なくreturnの先に定義されている”実は青く見えているだけなんだよ。”という文字列を返すことにします。この、returnの型を
func question(number int, text string) string {
の大括弧直前のstringで定義しています。
スコープ
rubyのローカル変数と同様、関数の中で指定された変数は、別の関数内で用いる事ができません。
defer
ざっくりいうと、関数の処理終わって直後に出力するように設定するよ。ってこと。
package main
import "fmt"
func main() {
defer fmt.Println("Sir")
defer fmt.Println("world")
fmt.Println("hello")
}
//出力結果
//→hello
// world
// Sir
deferがある時は、下から上に読んでいくと出力の順番がわかる。
deferへ渡した関数が複数の出力結果を持つ時
package main
import "fmt"
func main() {
defer fmt.Println("よーい")
for i := 0; i < 10, i++ {
defer fmt.Println(i) //for文で繰り返されるので、出力結果が複数になる。
}
fmt.Println("どん!")
}
//出力結果
//→よーい
// どん!
// 9 8 7 6 5 4 3 2 1 0
複数あるときは、最後の出力結果から吐き出される(LIFO)
ちなみに、この状態をstackと呼ぶらしい。
※LIFO = Last_In_First_Out(最後から入り、最初で終わり)
//ポインタ(Pointer)
pointerは、変数がメモリ上で持つアドレスのところまでいき、いろいろ作業したりするイメージです。
package main
import "fmt"
func main() {
y, k := 24, 4
p := &y // &をつけると、yのアドレスまでpが行ってくれます。
fmt.Println(*y) // yまで行ったpに、*で「値を教えて」とお願いします。
*p = 48 // yまで行った*pに、「yのアドレスにある(yという変数に格納されている)値を、48に変えて」と命令します。
fmt.Println(y) // pが変えてくれたyの値を出力します。
//出力結果
//→24
// 48
}
##構造体
こちらの記事によると
異なるデータの型の変数を一つにまとめたもの。
とあります。要は異なる型が集まった集合体のことです。RubyやPythonではクラスという概念があります。これは、なんらかの機能の塊を一つにまとめたものです。これに似た機能を、Goでは構造体が持ちます。
package main
import "fmt"
type Student struct {
name string
math, english float64
}
type User struct {
gender string
age int
}
このように、"type 構造体名 struct {}"のなかに定義する変数を記述していきます。
参考文献
- Goの基礎
https://astaxie.gitbooks.io/build-web-application-with-golang/content/ja/02.2.html - A Tour of Go
https://go-tour-jp.appspot.com/flowcontrol/13 - Go言語 - %Tや%vの書式で出力される文字列
https://blog.y-yuki.net/entry/2017/05/02/000000) - Go超入門コース#13 構造体
https://kino-code.com/course-go13-structure/