[Go]Webassembyのチュートリアル

GoでWebassemblyを使うためのチュートリアルとやってみた。
まずは公式のwikiを見ながら初めて、その中で紹介されてた簡単な計算機(足し算と引き算)の作成まで。


Hello world!

Goで書いたコードをビルドする。
コードは以下の通り、非常に簡単。"Hello world!"を出力するだけ。

package main
func main() {
	println("Hello world!")
}
GOOS=js GOARCH=wasm

"GOOS=js"、"GOARCH=wasm"を指定して、ビルドしてwasmファイル(といえばいいのか?)が出来上がる。

index.htmlを作成して、ビルドしたwasmファイルをロードする。
記載は以下の通り。とりあえず公式wikiの記載通り。

<html>
<head>
   <meta charset="utf-8">
   <script src="wasm_exec.js"></script>
   <script>
       const go = new Go();
       WebAssembly.instantiateStreaming(fetch("lib.wasm"), go.importObject).then((result) => {
           go.run(result.instance);
       });
   </script>
</head>
<body></body>
</html>

wasm_exec.jsファイルは、Goがインストールされているディレクトリの "misc/wasm"以下にあるので、index.htmlと同じディレクトリにコピーしておく。

HTTPサーバを起動する。
作業しているディレクトリに、server.goを以下の内容で作成し、起動する。

package main
import (
	"flag"
	"log"
	"net/http"
)
var (
	listen = flag.String("listen", ":8080", "Listen address")
	dir    = flag.String("dir", ".", "directory to server")
)
func main() {
	flag.Parse()
	log.Printf("listening on %q...", *listen)
	log.Fatal(http.ListenAndServe(*listen, http.FileServer(http.Dir(*dir))))
}


ブラウザから http://localhost:8080/index.html にアクセスすれば、コンソールに"Hello world!"と出力されているはず。

関数の使用

main.goを修正して、足し算用の関数を作成し、それをjsから呼び出せるようにする。

package main
import (
	"fmt"
	"syscall/js"
)
func add(this js.Value, i []js.Value) interface{} {
	js.Global().Set("output", js.ValueOf(i[0].Int()+i[1].Int()))
	fmt.Printf("%v\n", js.ValueOf(i[0].Int()+i[1].Int()))
	return nil
}
func registerCallbacks() {
	js.Global().Set("add", js.FuncOf(add))
}
func main() {
	c := make(chan struct{}, 0)
	println("Go WebAssembly Initialized")
	registerCallbacks()
	<-c
}

やっていることは、関数を定義してそれを"add"という関数名でjsから呼び出せるようにすること。

チュートリアルでは、関数の登録時に"js.NewCallback()"という関数を使用していたけど、現在は"js.FuncOf()"を使って登録するみたい。
※syscall/jsパッケージは冒頭に「This package is EXPERIMENTAL. Its current scope is only to allow tests to run, but not yet to provide a comprehensive API for users. It is exempt from the Go compatibility promise.」と注意書きがされている。

ビルドして、ブラウザをリロードする。
コンソールでadd関数が使用できるようになっていればOK。


DOMを操作

index.html を修正して、パラメータ二つと計算結果表示用のテキストボックスを追加する。Add/Subtructボタンも追加して、押したら計算wasmの関数を呼び出す。<body>

<body>
   <input type="text" id="v1" />
   <input type="text" id="v2" />

   <button onClick="add('v1', 'v2', 'result');" id="addButton">Add</button>
   <button onClick="subtract('v1', 'v2', 'result');" id="subtractButton">Subtract</button>

   <input type="text" id="result" />
</body>

main.goでDOMを参照して、パラメータの値を取得して、結果を出力する。
DOMを参照する処理をそのままGoで書いているだけという感じ。。。
以下はAdd関数。

func add(this js.Value, i []js.Value) interface{} {
	value1 := js.Global().Get("document").Call("getElementById", i[0].String()).Get("value").String()
	value2 := js.Global().Get("document").Call("getElementById", i[1].String()).Get("value").String()
	int1, _ := strconv.Atoi(value1)
	int2, _ := strconv.Atoi(value2)
	js.Global().Get("document").Call("getElementById", i[2].String()).Set("value", int1+int2)
	return nil
}


できた画面


感想など

・Goでwasmを使う場合のイメージが少しわかった。
・DOMの操作の仕方もわかった。
・大変そう。うまくやるライブラリがあるのだろうと思う。
・次はインタプリタをwasmで動かすというのをやってみようと思う。


この記事が気に入ったらサポートをしてみませんか?