[Golang]ポインタの挙動の確認

ポインタの挙動の確認。

ポイントは2つ

  • ポインタはアドレスを持つ
  • デリファレンスして実体を操作する

サンプル

func main() {
    var p *int // int型のポインタの宣言

    fmt.Println(p) // == nil

    v := 2
    fmt.Println(&v) // vのアドレス

    p = &v
    fmt.Println(p) // vのアドレスと同じ

    // *をつけるとデリファレンス(ポインタ型を通してデータ本体を参照すること)できる
    fmt.Println(*p) // == 2

    // pを通してvの値を更新
    *p = 5
    fmt.Println(v) // == 5

    // 関数を使ったポインタの挙動確認
    i := 1

    // 関数の引数は値コピーなので呼び出し元には関係ない
    inc(i)
    inc(i)
    fmt.Println(i) // == 1

    // ポインタを使って変更する
    inc_p(&i)
    inc_p(&i)
    inc_p(&i)
    fmt.Println(i) // == 4

}

func inc(i int) {
    i++
}

func inc_p(i *int) {
    *i++
}

ソースはこちら

iti

並列と並行の違い

並列(parallel) と 並行(concurrent)

『並行コンピューティング技法』より。

並行とは

システムが複数の動作を同時に実行状態に保てる機能を備えている場合

つまり、実際はシングルコアのCPUでマルチタスクの状態で複数のスレッドを順次切り替えているような状態でも、
複数のスレッドが実行状態になっていてそれを保持してるならそれは「並行」といえるということ。

並列とは

複数の動作を同時に実行できる場合

つまり、並列実行ではシステムにマルチプロセッサが必須。
実行状態ではなくまさに実行することができること。

並行は並列を包含する。

この本を読んでてなんか今までもやもやしている部分がスッキリしていきます。
面白い。

iti

[Golang]flagとテンプレート

Go言語によるwebアプリケーション
1.3.1 テンプレートの活用

べた書きしていたポートの指定をflagを使って実装する。
ついでに テンプレートでも使う。

フラグを使う

var addr = flag.String("addr", ":8080", "アプリケーションのアドレス")
flag.Parse() // flagを解釈します

こんな感じにすると、

./chat -addr=":3000"

みたいな感じで使える。
もしパラメータなしで起動した場合は初期値(例では8080)が使用される。

## テンプレートを使う

テンプレートには以下の形式でデータを埋め込める。

{{ }}

 こんな感じ。

socket = new WebSocket("ws://{{.Host}}/room");

ソースはこちら

iti

[Golang]mapの挙動の確認

mapの挙動の確認。

省略記法が便利。

package main

import (
    "fmt"
)

func main () {
    // 宣言
    //var m map[int]string

    // makeで作る
    m := make(map[int]string)

    m[1] = "hogehoge"
    m[30] = "hugahuga"
    m[-1] = "hahahah"

    fmt.Println(m)

    // mapリテラルで作る
    m2 := map[string]string{
        "us": "america", 
        "jp": "japan", 
        "hoge": "hogehoge", // カンマが必要
    }

    fmt.Println(m2)

    // sliceをもつmap
    m3 := map[int][]int {
        1: []int{1},
        2: []int{1,3},
        3: {4,3,3}, // 省略することも可能
    }

    fmt.Println(m3)

    // mapの要素がmapの場合 宣言が複雑なのは仕方ないのか。。
    m4 := map[int]map[float64]string {
        1: { 3.14 : "円周率" },
    }

    fmt.Println(m4)

    // 要素の参照時にキーがない場合に初期値が返されてしまう。
    // その回避方法
    m5 := map[int]string{1: "a", 2: "b", 3: "c"}
    s, ok := m5[1]
    fmt.Println(s,ok)
    s2, ok2 := m5[5]
    fmt.Println(s2,ok2)

    // よくある書き方
    if _, ok := m5[2]; ok {
        // キーが存在する場合に処理
        fmt.Println("キーが存在するよ")
    }

    // forで回す
    // キーの順序は保証されない
    for k,v := range m2 {
        fmt.Println(k,v)
    }

    // 要素を削除する
    delete(m5, 2)
    fmt.Println(m5)
}

[Golang]sliceの挙動を確認した

ざっくりスライスの挙動を確認。

ポイントは、
– 配列とは別物(値だし)
– 参照型
– 可変長

package main

import (
    "fmt"
)
/*
参照型 は 3種類
1. slice
2. map
3. channel

ここではslice
*/
func main() {

    // int型のslice
    // var s []int // 宣言
    s := make([]int, 10)

    // 配列と似ているが、型として別物
    fmt.Println(s)
    fmt.Println(len(s))

    s2 := make([]int, 5, 10)
    fmt.Println(s2)
    fmt.Println(len(s2))
    fmt.Println(cap(s2))

    // makeを使用しないスライスの生成方法
    s3 := []int{1,2,3,4,5}
    fmt.Println(s3)
    fmt.Println(len(s3))
    fmt.Println(cap(s3))

    // 簡易スライス式
    a := [5]int{1,2,3,4,5}
    s4 := a[0:2]
    fmt.Println(s4)

    s4 = append(s4, 5)
    fmt.Println(s4)
    fmt.Println(a)

    // スライスと可変長引数
    fmt.Println(sum(1,2,3,4))
    fmt.Println(sum(1,2,3,4,6,7,8,98))
}


// 可変長引数サンプル
// 可変長引数は引数の末尾に一つだけ定義できる
func sum(s ...int) int {
    n := 0
    for _,v := range s {
        n += v
    }
    return n
}

ソースはこちら

[Golang]rangeについて

  • rangeは複数の要素を保持する性質を備えるデータ型に使える
  • 配列型で使うのがイメージ湧きやすいが、string型でも使える。
  • というか、色々使える
package main

import (
    "fmt"
)

func main() {
    fruits := [3]string{"apple", "banana", "grape"}

    for i, s := range fruits {
        // i はindex
        // s は要素
        fmt.Printf("fruits[%d]=%s\n", i, s)
    }

    // rangeは複数の要素を保持する性質を備えるデータ型に使える
    // 文字列型をrangeで使うとrune型で取り出す
    strings := "あいうえお"
    for i, s := range strings{
        fmt.Printf("strings[%d]=%s %#U\n", i, s, s)
    }
}

ソースはこちら

もうちょっと丁寧に調べないと。

iti