Golangの構造体、値のスライスとポインタのスライス

構造体の値のスライスとポインタのスライス、どちらがいいのか?

こんな構造体とJSON文字列を定義して…

type Hoge struct {
    Nyan int64
    Wang string
}

const jsonStr = `[{"nyan":1, "wang":"aaaa"}, {"nyan":1, "wang":"bbbb"}]`

ポインタのスライスの場合

var a []*Hoge

json.Unmarshal([]byte(jsonStr), &a)

for i, h := range a {
    h.Nyan *= 2
    h.Wang += h.Wang
        fmt.Println(h == a[i])
        fmt.Println(*h == *a[i])
}

fmt.Println(a[0].Nyan, a[0].Wang)
fmt.Println(a[1].Nyan, a[1].Wang)

結果

2 aaaaaaaa
4 bbbbbbbb

ループの中での変更は反映される。まあポインタだから当然。

値の場合

var b []Hoge

json.Unmarshal([]byte(jsonStr), &b)

for _, h := range b {
    h.Nyan *= 2
    h.Wang += h.Wang
}

fmt.Println(b[0].Nyan, b[0].Wang)
fmt.Println(b[1].Nyan, b[1].Wang)

結果

1 aaaa
2 bbbb

ループの中での変更は反映されていない。つまりループ変数の h には構造体がコピーされて渡されているということ。巨大な構造体のスライスをループさせるとコピーの負荷がそれなりに発生しそう。特に理由がなければポインタのスライスにしたほうが良さそう。

JSコード片をObjectURL化してWeb Workerで実行

今Web WorkerといえばService Workerの話題ばかりですが、これからするのは普通のWorker(Dedicated Worker)の話です。

Web Workerはバックグラウンドでスクリプトを実行できるものです。

重い処理をJSで実行するとUIが固まって何の操作も受け付けなくなりますが、Workerは別スレッドで実行するのでUI処理に影響することはありません。UIに影響しないようにDOMにアクセスできないなどの制限がありますが、ArrayBufferを渡してバイナリ処理をしたり、fetch APIを使ってデータを取得して処理したり、できることはいろいろあります。

https://developer.mozilla.org/ja/docs/Web/API/Web_Workers_API

普通は以下のように別のスクリプトファイルを指定して使いますが…

const worker = new Worker("worker.js");

// ワーカー内でpostMessageが呼ばれた時のハンドラ
worker.onmessage = function(e) {
   window.alert(e.data);
}

// ワーカーにデータを渡す
worker.postMessage("1 + 1");

URL.createObjectURLを使ってURL化したコード片も渡すことができます。

const source = "(" + function() {
    onmessage = function(e) {
        const f = new Function("js", "return eval(js)");
        postMessage(f(e.data));
    }
} + ")();"

const url = URL.createObjectURL(new Blob([source], { type: "application/javascript" }));

const worker = new Worker(url);

worker.onmessage = function(e) {
   window.alert(e.data);
}

worker.postMessage("1 + 1");