golang 1.5 から、x86_64 のみですが -buildmode=c-shared
というビルドオプションが足される事になりました。
これは、golang で共有ライブラリを生成する為のオプションで、例えば
package main
import (
"C"
"fmt"
)
var (
c chan string
)
func init() {
c = make(chan string)
go func() {
n := 1
for {
switch {
case n%15 == 0:
c <- "FizzBuzz"
case n%3 == 0:
c <- "Fizz"
case n%5 == 0:
c <- "Buzz"
default:
c <- fmt.Sprint(n)
}
n++
}
}()
}
//export fizzbuzz
func fizzbuzz(n int) *C.char {
return C.CString(<-c)
}
func main() {
}
こういう golang のコードlibfizzbuzz.go
があったとして
$ go build -buildmode=c-shared -o libfizzbuzz.so libfizzbuzz.go
この様にビルドすると libfizzbuzz.so
が出力されます。python を使えば
from ctypes import *
lib = CDLL("./libfizzbuzz.so")
lib.fizzbuzz.restype = c_char_p
print lib.fizzbuzz()
print lib.fizzbuzz()
print lib.fizzbuzz()
print lib.fizzbuzz()
print lib.fizzbuzz()
print lib.fizzbuzz()
1
2
Fizz
4
Buzz
Fizz
この様に関数を呼ぶ度に FizzBuzz が生成される関数も簡単に作れます。Vim には if_python という python 拡張もありますのでこれを使えば Vim プラグインの機能の一部として golang を使う事が出来る様になります。新しめの Vim であれば if_python はスレッドセーフなので
mattn/vim-go-fizzbuzz - GitHub
https://github.com/mattn/vim-go-fizzbuzz
let s:libdir = expand('<sfile>:p:h:h') . '/go'
if !filereadable(s:libdir . '/libfizzbuzz.so')
exe "!cd " . s:libdir . " && make"
endif
function! fizzbuzz#start()
python<<EOS
import vim
import thread
import time
from ctypes import *
libfizzbuzz = CDLL(vim.eval('s:libdir') + '/libfizzbuzz.so')
libfizzbuzz.fizzbuzz.restype = c_char_p
def run():
while True:
vim.eval("fizzbuzz#on_fizzbuzz('%s')" % libfizzbuzz.fizzbuzz())
time.sleep(1)
thread.start_new_thread(run, ())
EOS
endfunction
function! fizzbuzz#on_fizzbuzz(s)
if mode() != 'n'
return
endif
echo a:s
endfunction
1秒に1回、golang の goroutine で非同期にループしながら channel を経由して渡される FizzBuzz を、python のスレッドを介して Vim のメッセージが表示されるという、一見誰の役にも立ちそうにない事ながら未来感が溢れてきますね。どうしても python を書きたくない、でも非同期がやりたい!golang が書きたい!という人にはとても良い時代になってきました。もうすぐ、いろんなライブラリを golang だけで書ける日がやってきそうです。
ちなみに、libcallex-vim というプラグインを使えば
let fizzbuzz = libcallex#load("/home/mattn/dev/go-sandbox/libfizzbuzz.so")
echo fizzbuzz.call("fizzbuzz", [], "string")
echo fizzbuzz.call("fizzbuzz", [], "string")
echo fizzbuzz.call("fizzbuzz", [], "string")
echo fizzbuzz.call("fizzbuzz", [], "string")
echo fizzbuzz.call("fizzbuzz", [], "string")
echo fizzbuzz.call("fizzbuzz", [], "string")
if_python も使わなくても(ただしCライブラリのビルドが必要) FizzBuzz 出来ますね。