20190126のGoに関する記事は4件です。

TILE38紹介(2) :空間系コマンド

TL;DR

  • 前回記事で基本的なコマンドとして点データの格納と距離にとる参照を紹介した。今回は線やポリゴン(多角形)のデータの格納と検索を実現するコマンドを紹介する。

コマンド

コマンド どんな機能
WITHIN 指定された地図条件範囲内のデータの検索
INTERSECTS 線や多角形などの図形と直行するデータまたは含まれるデータの検索

バウンダリの検索

  • 複数個登録した境界(バウンダリ:東西南北に沿った境界線)を中心点からの距離で検索する。
127.0.0.1:9851> SET example bounds:X BOUNDS 35.6578 139.6971 35.6581 139.6968
{"ok":true,"elapsed":"6.335µs"}
127.0.0.1:9851> SET example bounds:Y BOUNDS 35.6572 139.6984 35.6575 139.6978
{"ok":true,"elapsed":"3.575µs"}
127.0.0.1:9851> SET example bounds:Z BOUNDS 35.6590 139.6967 35.6594 139.6959
{"ok":true,"elapsed":"13.362µs"}
127.0.0.1:9851> WITHIN example IDS CIRCLE 35.6581 139.6975 120
{"ok":true,"ids":["bounds:X"],"count":1,"cursor":0,"elapsed":"66.094µs"}

  • バウンダリを3つ登録して、WITHIN検索を実行した。
  • WITHINでは現在地から半径120メートルを検索範囲とした。
  • WITHINは検索範囲内に完全に含んでいるオブジェクトを対象とするため、図の領域Xのみが検索結果となり、領域Y、Zは結果に入らない。
  • NEARBYとの違いは、点だけではなく平面領域を検索対象とできることである。

Screen Shot 2019-01-26 at 10.45.39.jpg

127.0.0.1:9851> INTERSECTS example IDS CIRCLE 35.6581 139.6975 120
{"ok":true,"ids":["bounds:X","bounds:Y"],"count":2,"cursor":0,"elapsed":"43.576µs"}
  • コマンドをINTERSECTSにした場合は、検索範囲にオブジェクトの一部でも含まれていると検索結果の対象となることである。

Screen Shot 2019-01-26 at 10.36.39.jpg

線やポリゴンの検索

  • TILE38の点(POINT),バンダリ(BOUNDS)を使用してきたが、GeoJsonを使用することで線やポリゴンなどの複雑な領域の検索が実現できることを説明する。
  • GeoJsonは空間データとその属性情報に関するJSON形式のファイルフォーマットである。(Wikipedia)
  • 空間データとしては点、線、ポリゴン(多角形)とその組み合わせを扱うことができる。
  • 以下では検索基準となる領域となるポリゴンと、検索対象となる線、ポリゴンをデータベースに格納し、INTERSECTSコマンドで検索する。
127.0.0.1:9851> SET location me OBJECT {"type":"Polygon","coordinates":[[[35.6590,139.6982],[35.6589,139.6978],[35.6577,139.6965],[35.6574,139.6964],[35.6572,139.6966],[35.6575,139.6973],[35.6580,139.6988],[35.6587,139.6984],[35.6590,139.6982]]]}
{"ok":true,"elapsed":"67.481µs"}
127.0.0.1:9851> SET example polygon:P OBJECT {"type":"Polygon","coordinates":[[[35.6587,139.6984],[35.6590,139.6983],[35.6589,139.6979],[35.6586,139.6980],[35.6587,139.6984]]]}
{"ok":true,"elapsed":"43.118µs"}
127.0.0.1:9851> SET example polygon:Q OBJECT {"type":"Polygon","coordinates":[[[35.6591,139.6967],[35.6595,139.6960],[35.6589,139.6958],[35.6586,139.6965],[35.6591,139.6967]]]}
{"ok":true,"elapsed":"37.007µs"}
127.0.0.1:9851> SET example road:R OBJECT {"type":"LineString","coordinates":[[35.6584,139.6954],[35.6567,139.6970]]}
{"ok":true,"elapsed":"29.312µs"}
127.0.0.1:9851> SET example road:S OBJECT {"type":"LineString","coordinates":[[35.6585,139.6994],[35.6575,139.6953]]}
{"ok":true,"elapsed":"55.785µs"}
127.0.0.1:9851> INTERSECTS example IDS GET location me
{"ok":true,"ids":["polygon:P","road:S"],"count":2,"cursor":0,"elapsed":"71.981µs"}
  • 検索基準となる領域(KEY:location,ID:me)として複雑な多角形(図:緑色)について、複数の検索対象(KEY:example)を検索した。
  • 各領域はTILE38ではOBJECTとしてGeoJson形式でパラメータを渡して格納する。
  • バウンダリの場合と同様に検索基準に全部または一部が含まれる領域が検索結果に含まれる。(図:青色)逆に検索基準に一部も含まれない領域(図:赤色)は検索結果に含まれない。

Screen Shot 2019-01-26 at 16.49.27.jpg

次章予定

  • Redisクライアントライブラリを使用したGoプログラムからのアクセス。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Golang】Interfaceの条件を満たしているかどうかをチェックする

type assertionを使うことで、変数の型を調べることができるが、同様にその構造体が特定のInterfaceの条件を満たしているかどうかのチェックをすることができる。

main.go
package main

import (
    "fmt"
)

type InterfaceA interface {
    doSomething()
}

//----InterfaceAの条件を満たす構造体Aを作成------
type A struct {
}

func (a A) doSomething() {
    fmt.Println("A has a doSomething method")
}
func tt(a InterfaceA) {
    a.doSomething()
}

func main() {
    //--interface{}として宣言--
    var a interface{}
    a = A{}
    if p, ok := a.(InterfaceA); ok {
        //--変数pはA型の構造体!!---
        p.doSomething()
    }
}
実行結果
A has a doSomething method

interface型を受け取って、受け取ったものが満たしているinterface型に応じて処理内容を変更したりできる

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rust-gdb を真似たgo-gdbという簡単gdb起動スクリプト

gdbでgolangをデバッグする方法

gdbでgolangをデバッグする方法は公式ドキュメントに書かれています。
Debugging Go Code with GDB

しかし、オプションをつけたり、.gdbinit を作ったりしなくてはならないのでちょっと面倒くさい。
gdbでRustをデバッグするときもそのあたりの事情は同じはずなのですが、rust-gdbというコマンドがそのややこしさを隠蔽してくれています。

go-gdbスクリプト

rust-gdb のshellスクリプト実装を見つけました。
https://github.com/rust-lang/rust/blob/master/src/etc/rust-gdb
これを真似てgolang用のものを作りました。

go-gdb
#!/bin/sh
set -e
GOROOT=`go env GOROOT`

GO_GDB="${GO_GDB:-gdb}"
exec ${GO_GDB} \
  --directory="$GOROOT" \
  -iex "add-auto-load-safe-path $GOROOT/src/runtime/runtime-gdb.py" \
  "$@"

gistにも置きました。
https://gist.github.com/tetsu-koba/648166471d7c3db6f02aa1ffec1f0259

これをPATHの通ったディレクトリに置く。(例えば ~/bin )

使用例

$ go-gdb hello
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from hello...done.
Loading Go Runtime support.
(gdb) 

このように起動した時にLoading Go Runtime support. が出ていればOK。
golangのmain関数の先頭まで実行してブレークさせるにはstartコマンドが便利。

(gdb) start
Temporary breakpoint 1 at 0x483880: file /home/koba/go/src/hello/hello.go, line 5.
Starting program: /home/koba/go/src/hello/hello 
[New LWP 2361]
[New LWP 2362]
[New LWP 2363]

Thread 1 "hello" hit Temporary breakpoint 1, main.main ()
    at /home/koba/go/src/hello/hello.go:5
5   func main() {
(gdb) 

goroutineの一覧を見るにはinfo goroutine。省略してinfo go でもOK。

(gdb) info go
* 1 running  runtime.systemstack_switch
  2 waiting  runtime.gopark
  17 waiting  runtime.gopark
  18 waiting  runtime.gopark
(gdb) 

残念ながらgoroutineの切り替えはエラーになってしまって現状は使えない。

(gdb) goroutine 2
Python Exception <class 'ValueError'> not enough values to unpack (expected 2, got 1): 
Error occurred in Python command: not enough values to unpack (expected 2, got 1)
(gdb) 

emacsの中からgo-gdb を起動する

M-x gdb

を実行して、

Run gdb (like this): gdb -i=mi hello

これを以下のように書き換えるだけ。

Run gdb (like this): go-gdb -i=mi hello

参考。
emacsの中からrust-gdbを起動する

補足情報

gdbはpython拡張機能が有効になったものが必要です。ubuntuのaptでインストールできるものはそうなっているので大丈夫。
自分でgdbをビルドする時には、sudo apt install libpython-dev をしておくこと。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

chroma をつかってコードハイライトを生成するサンプル

go のコードの一部です。

type Ping struct {
    Status int
    Result string
}

func Sample(w http.ResponseWriter, r *http.Request) {
    lexer := lexers.Get("ruby")
    style := styles.Get("monokai")
    if style == nil {
        style = styles.Fallback
    }
    formatter := html.New(html.WithClasses())
    iterator, err := lexer.Tokenise(nil, "def hoge; x=3; 6; end")
    buf := new(bytes.Buffer)
    err = formatter.Format(buf, style, iterator)
    if err != nil {
        fmt.Println(err)
    }

    sourceCode := buf.String()
    ping := Ping{http.StatusOK, sourceCode}
    res, _ := json.Marshal(ping)
    w.Header().Set("Content-Type", "application/json")
    w.Write(res)
}

これで、以下のような json を得る。

image.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む