覚えたら書く

IT関係のデベロッパとして日々覚えたことを書き残したいです。twitter: @yyoshikaw

Go言語 - マップの基本的な操作

Go言語で提供される map について基本的な操作を試してみます。

以下map生成のサンプル以外は基本的に package, import 部分の記述は省略しています


mapの生成

makeで生成

make関数を使って make(map[<キーの型>]<値の型>) を実行することで mapを生成することができます

■サンプルコード

package main

import "fmt"

func main() {
    m := make(map[string]int)

    fmt.Println(m)

    m["key1"] = 10
    m["key2"] = 20

    fmt.Println(m)
}

■実行結果

map[]
map[key1:10 key2:20]


マップリテラルで生成

map[<キーの型>]<値の型>{<キー>: <値>, <キー>: <値>, ...} で初期値をセットしたmapを作ることができます

package main

import "fmt"

func main() {
    m := map[string]int{
        "key1": 10,
        "key2": 20,
        "key3": 300,
        "key4": 400,
    }

    fmt.Println(m)
}

■実行結果

map[key3:300 key4:400 key1:10 key2:20]


値の取得

マップ[<キー>] でmapから対応する値を取得できます

■サンプルコード

func main() {
    m := map[string]int{
        "key1": 10,
        "key2": 20,
        "key3": 300,
        "key4": 400,
    }

    fmt.Println(m)

    // mapから値を取得
    fmt.Println(m["key2"])
    fmt.Println(m["key3"])
    fmt.Println(m["key99"])
}

■実行結果

マップ内に存在しないキーを使って、マップから値を取得しようとするとマップのエントリの型のゼロ値が返されます。
今回のサンプルでは “key99"(という存在しないキー)に対して 0 という値が返ってきています。

map[key2:20 key3:300 key4:400 key1:10]
20
300
0


値の存在チェック

マップ内に指定のキーに対する値が存在しているかは、戻り値を2つ受けて、2番目の戻り値で判断することができます。
val, ok = m[key]のような記述をして、「カンマok」慣用句と呼ばれるようです。
値が存在するなら ok はtrueとなり、そうでなければfalseとなります。

■サンプルコード

func main() {
    m := map[string]int{
        "key1": 10,
        "key2": 20,
        "key3": 300,
        "key4": 400,
    }

    value, ok := m["key2"]
    fmt.Printf("key2 -> exists=%t, value=%d\n", ok, value)

    value, ok = m["key99"]
    fmt.Printf("key99 -> exists=%t, value=%d\n", ok, value)

        // 値が存在するなら処理を行う
    if val, ok := m["key1"]; ok {
        fmt.Printf("key1 exists. value = %d\n", val)
    }
}

■実行結果

key2 -> exists=true, value=20
key99 -> exists=false, value=0
key1 exists. value = 10


値のセット

マップ[<キー>]=<値> で値をセットできます。エントリの新規追加も既存エントリの上書きのいずれもこの構文になります

■サンプルコード

func main() {
    m := map[string]int{
        "key1": 10,
        "key2": 20,
        "key3": 300,
        "key4": 400,
    }

    fmt.Println(m)

    m["key5"] = 500   // 新規追加
    m["key1"] = 10000 // 上書き

    fmt.Println(m)
}

■実行結果

map[key1:10 key2:20 key3:300 key4:400]
map[key1:10000 key2:20 key3:300 key4:400 key5:500]


エントリの削除

■サンプルコード

delete関数を用いて delete(<マップ>, <キー>)で対象のエントリを削除することができます

func main() {
    m := map[string]int{
        "key1": 10,
        "key2": 20,
        "key3": 300,
        "key4": 400,
    }

    fmt.Println(m)

    // 要素の削除
    delete(m, "key4")
    delete(m, "key99")

    fmt.Println(m)
}

■実行結果

map[key3:300 key4:400 key1:10 key2:20]
map[key1:10 key2:20 key3:300]


全エントリにアクセス

rangeを使用して、 for key, value := range マップ { <処理> } と記述することでマップ内の全エントリにアクセスして処理を行うことができます

■サンプルコード

func main() {
    m := map[string]int{
        "key1": 10,
        "key2": 20,
        "key3": 300,
        "key4": 400,
    }

    // 全エントリにアクセスして処理を実行
    for key, value := range m {
        fmt.Printf("key:%s -> value=%d\n", key, value)
    }
}

■実行結果

key:key4 -> value=400
key:key1 -> value=10
key:key2 -> value=20
key:key3 -> value=300


マップの要素数

マップに登録された要素の数を取得するにはlen関数を利用して、len(マップ)を実行することで取得できます

■サンプルコード

func main() {
    m := map[string]int{
        "key1": 10,
        "key2": 20,
        "key3": 300,
        "key4": 400,
    }

    fmt.Printf("element count: %d\n", len(m))
}

■実行結果

element count: 4

Go言語 - Windowsのexe実行時にコマンドプロンプトを表示しないようにする

Go言語で単純にビルドしたWindows用のexeを実行すると、コマンドプロンプトの画面(DOS窓)が表示されてしまいます。

ツール作ってる時は別にそれでも大丈夫ということもありますが、GUIアプリケーションなどの場合は邪魔でしかないです。


exe実行時にコマンドプロンプトの画面を表示させないようにするためには以下のようなビルドを行います。

go build -ldflags="-H windowsgui"


これにより、生成したexeを実行してもコマンドプロンプトの画面は表示されなくなります。

Go言語 - WebSocketのクライアントでJSONメッセージをやり取りしてみる

golang.org/x/net/websocketパッケージでWebSocketクライアント側の実装サンプルです。
(WebSocketサーバ側は別に存在していて、クライアントから送られたメッセージオウム返しするEchoServerになっているものとします)


■サンプルコード

大まかに、websocket.DialでWebSocketのクライアントを生成してコネクション確立し、websocket.Connを通じてメッセージの送受信を行うという流れになっています。

実際に送受信するメッセージはJSON形式として、websocket.JSON.Sendでサーバへのメッセージ送信、websocket.JSON.Receiveでサーバからのメッセージ受信を行います

package main

import (
    "log"
    "time"

    "golang.org/x/net/websocket"
)

var (
    origin = "http://localhost:8787/"
    url    = "ws://localhost:8787/echo"
)

// EchoMsg is Sample Websocket Message
type EchoMsg struct {
    Msg string // メッセージ
    ID  int32  // ID
}

func main() {
    ws, err := websocket.Dial(url, "", origin)
    if err != nil {
        log.Fatal(err)
    }

    go receiveMsg(ws)

    sendMsg(ws, "Hello", 1)
    sendMsg(ws, "Goodbye", 2)

    time.Sleep(1 * time.Second)
    _ = ws.Close()

    defer log.Printf("Web Socket Client Sample end.")
}

func sendMsg(ws *websocket.Conn, msg string, id int32) {
    var sndMsg = EchoMsg{msg, id}

    websocket.JSON.Send(ws, sndMsg)
    log.Printf("Send data=%#v\n", sndMsg)
}

func receiveMsg(ws *websocket.Conn) {
    var rcvMsg EchoMsg
    for {
        websocket.JSON.Receive(ws, &rcvMsg)
        log.Printf("Receive data=%#v\n", rcvMsg)
    }
}

sendMsgがサーバへメッセージ送信をする部分で、receiveMsgでサーバからのメッセージを受信している部分になります。
(サーバからのメッセージを全て受信するために1秒だけスリープしています。あまり本質的なものではありません)


■実行結果

上記サンプルの実行結果は以下の通りです

2017/04/24 05:55:09 Send data=main.EchoMsg{Msg:"Hello", ID:1}
2017/04/24 05:55:09 Receive data=main.EchoMsg{Msg:"Hello", ID:1}
2017/04/24 05:55:09 Send data=main.EchoMsg{Msg:"Goodbye", ID:2}
2017/04/24 05:55:09 Receive data=main.EchoMsg{Msg:"Goodbye", ID:2}
2017/04/24 05:55:10 Web Socket Client Sample end.

無事にWebSocketサーバとメッセージの送受信ができました


補足

本エントリのサンプルでは、コネクションが切れた場合の再接続処理など考慮しなければならない点が諸々抜けています。
(Go言語歴がまだ浅い私が書いたサンプルですので、ご注意ください)


今回利用したgolang.org/x/net/websocket以外にもgorilla/websocketといったWebSocketのライブラリも存在しているようです。
こちらの方がかなり機能が豊富なようです



関連エントリ

Go言語 - rsrcを使ってexeにアイコンを埋め込む

go buildして生成するexeファイルにアイコンをファイルをrsrcを使って埋めこむ手順です


アイコンファイルの用意

exeに埋め込むためのアイコンファイル(.ico)を用意してください

ここでは、SampleApp.ico を用意したものとします


rsrcの入手とexe化

以下の手順でrsrcを取得してビルドします

go get -v github.com/akavel/rsrc
cd %GOPATH%/src/github.com/akavel/rsrc
go build

これでrsrc.exeができるので、このファイルをPATHが通ったディレクトリに配置します。


アイコンファイルの埋め込みとビルド

ビルド対象のgoファイルがあるディレクトリへ移動して以下を実行します

rsrc -ico SampleApp.ico -o SampleApp.syso
go build

これで生成されたexeに対象のアイコンファイルが埋め込まれた状態になっています

Go言語 - WindowsのセッションID取得

Windowsではログオンしたユーザごとにセッションが存在しています。(セッション 0 の分離 - Windows 7 対応アプリケーションの互換性

そのセッションのセッションIDをGo言語で取得するサンプルです。

本サンプルでは自プロセスIDを元にそのプロセスが存在しているセッションのセッションIDを取得します


■サンプルコード

package main

import (
    "fmt"
    "os"
    "syscall"
    "unsafe"
)

func abort(funcname string, err error) {
    panic(fmt.Sprintf("%s failed: %v", funcname, err))
}

var (
    kernel32, _ = syscall.LoadLibrary("kernel32.dll")

    processIDToSessionID, _ = syscall.GetProcAddress(kernel32, "ProcessIdToSessionId")
)

func main() {
    fmt.Printf("My Session Id: %d", MySessionID())
}

func MySessionID() uint32 {
    var sessionID uint32
    _, _, callErr := syscall.Syscall(uintptr(processIDToSessionID),
        2,
        uintptr(os.Getpid()),
        uintptr(unsafe.Pointer(&sessionID)),
        0)
    if callErr != 0 {
        abort("Call ProcessIdToSessionId", callErr)
    }
    return sessionID
}

単純に、os.Getpidの結果を引数にして、WindowsAPIのProcessIdToSessionIdを呼び出しているだけです。(ProcessIdToSessionId 関数


■実行結果

My Session Id: 1

無事にセッションIDが取得できました



関連エントリ