LoginSignup
2

More than 5 years have passed since last update.

Go言語始めて1週間のメモ

Last updated at Posted at 2018-08-16

Go言語に特有な部分にフォーカスしてつらつらと書いていきます。

変数宣言の省略

number := 100 // var int number = 100

※使っていない変数があるとエラーをはく

複数のパッケージ名・変数宣言

() で囲う

import (
    fmt
    math
)

const (
    Small = 1
    Medium = Small << 10
    Large = Medium << 10
)

slice

要素数を書くと配列、書かないとスライスになる。

// array
ary := [...]int{1, 3, 5, 7, 10}

// slice
s := []int{1, 3, 5, 7, 10}

基本的にはスライスの方が多く使われる。
スライスは append()copy() が使える。

ハッシュ中の値の有無

// map = 連想配列、ハッシュ
m := map[string]int{
    "sato":   100,
    "suzuki": 200}
value, ok := m["sato"]
fmt.Println(value, ok) // 100 true 存在しない場合は 0 false

制御文の中に変数を書ける

if n := 100; n > 50 {
    fmt.Println("Good!!")
}
fmt.Println(n) // undefined

変数のスコープは違うが、以下と同じ意味

n := 100
if n > 50 {
    fmt.Println("Good!!")
}
fmt.Println(n) // 100

forの省略

// 初期化と処理後の処理の省略が可能
i := 0
// whileと同じ処理になる(Go言語にはwhileがない)
for i < 10 {
    i++
}
無限ループ
for {
    // 処理
}

range

スライス、マップなどを要素数分ループさせるキーワード。

スライス
s := []string{"red", "blue", "yellow"}
// '_'はワイルドカード
for _, value := range s {
    fmt.Println(value)
}
マップ
m := map[string]int{
    "sato":   100,
    "suzuki": 200}
for k, value := range m {
    fmt.Println(k, value)
}

メソッドとレシーバ

メソッド:構造体などのデータ型に紐づいた関数

レシーバ:メソッドを呼び出される対象

type user struct {
    name  string
    score int
}

// 値渡し
func (u user) show() {
    fmt.Println(u.name, u.score)
}

// ポインタ渡し
func (u *user) add() {
    // 元の値を書き換える
    // ポインタ変数にしないとscore=10のまま
    u.score++
}

func main() {
    u := user{
        name:  "sato",
        score: 10,
    }
    u.add()
    u.show()
}

空のインターフェース

空のインターフェースを利用すると、
あらゆる型を受け付ける関数をつくることができる。

一方、型の動的チェックをするために、
if文の「型アサーション」と、
switch文の「型switch」が提供されている。

// あらゆる型を受け付ける関数
func anyFunc(any interface{}) {

    // 型アサーション
    if _, ok := any.(string); ok {
        fmt.Println("this is string")
    } else {
        fmt.Println("this is not string")
    }

    // 型switch
    switch any.(type) {
    case string:
        fmt.Println("this is string")
    default:
        fmt.Println("this is not string")
    }
}

func main() {
    anyFunc("空のインターフェース")
}

goroutine

並行処理(順不同に行う処理)を実現する

func task1() {
    // 重い処理の想定で1秒待つ
    time.Sleep(time.Second)
    fmt.Println("task1 finished...")
}
func task2() {
    fmt.Println("task2 finished...")
}
func main() {
    go task1()
    go task2()

    // 上記関数が終わる前にmain関数が終わってしまうのを防ぐ
    time.Sleep(time.Second * 3)
}

task1()、task2()が走り、
すぐにtask2()が終わり、1秒後にtask1()が終わる。

channel

goroutine間におけるデータを受け渡しするパイプ

送信:channel<-value
受信:<-channel

func task1(ch chan string) {
    time.Sleep(time.Second)
    // 値をチャネルへ送信
    ch <- "task1 finished..."
}
func task2() {
    fmt.Println("task2 finished...")
}
func main() {
    // チャンネルを宣言
    ch := make(chan string)
    go task1(ch)
    go task2()

    // チャネルから受信
    fmt.Println(<-ch)
    // 受信するまで処理が止まっているのでtime.Sleep()は不要
}

task1()、task2()が走り、すぐにtask2()は終わる。
1秒後にtask1()の処理が進み、データをチャネルへ送信。
main関数の中でチャネルからデータを受信し、全体の処理が終了。

defer

defer へ渡した関数の実行を、呼び出し元の関数の終わり(returnする)まで遅延させる。
つまり、その関数が終了する際に実行したい処理を記述することができる。
複数の関数を渡した場合はLIFOの順番で実行される。

func main() {
    defer fmt.Println("world")

    fmt.Println("hello")
}
出力
hello

world

参考
A Tour of Go
dotinstall Go言語入門

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2