fkm 〜 Super Software Entertainerへの道 〜 このページをアンテナに追加 RSSフィード

本ブログはfkmsoft blogに移行します。

 

2015-09-08 GoのASTをちょっと触ってみる

[][]GoのASTをちょっと触ってみる GoのASTをちょっと触ってみるを含むブックマーク

「やってみた」系の記事はときどきここに書きます.

Goソースファイルを食べさせるとASTにしてくれるライブラリが標準であります. ここまではちょっとぐぐると出てくる.

package main

import (
        "go/parser"
        "go/token"
)

func main() {
        src := "package model\n" +
                "type Moke struct{\n" +
                "  Name string `myTag`\n" +
                "  Age int\n" +
                "}\n"
        fset := token.NewFileSet()
        f, err := parser.ParseFile(fset, "", src, 0)
        if err != nil {
                return
        }
        // fの型は*ast.File型
        // このfを覗くといろいろ取れるはずだが。。。
}

で, この後「このASTをどうやって扱うか?」があんまり例としてでてこなかったのでここに書いてみる.

構造体を認識してみる

入力となるファイルを次のような構造体が1つ定義されているだけのものとする.

package model

type Moke struct{
  Name string `myTag`
  Age int
}

ast.File型には, トップレベルでの宣言がスライスで入っている. 今回の構造体もトップレベルで宣言されているので, きっとこの中に入っているはず.

ということでまずはforで1つずつ中身を見てみる.

for _, decl := range f.Decls {
    // declはast.Decl型. これはinterfaceなので実際にはいろんな型
}

いろんな宣言がとれるので, ここでは構造体のときにでてくる*ast.GenDeclを探す. GenDeclは「一般的な宣言」ノードなので, importとかもこれになるっぽい. なのでtypeであるものを探す.

for _, decl := range f.Decls {
        genDecl, ok := decl.(*ast.GenDecl)
        if !ok {
                continue
        }
        if genDecl.Tok != token.TYPE {
                continue
        }
}

型宣言であることまでわかったので, どんな型宣言なのかをgenDecl.Specsを覗いて調べる。genDecl.Specsはast.Specスライス.

for _, spec := range genDecl.Specs {
     // specの型はast.Spec型^H. interfaceなので実際はImportSpecやTypeSpecなど
}

ast.TypeSpecであるかを一応調べ, TypeSpecの場合はstructであるかを調べる.

for _, spec := range genDecl.Specs {
        typeSpec, ok := spec.(*ast.TypeSpec)
        if !ok {
                continue
        }
        // 宣言した構造体名
        name := typeSpec.Name.Name 
        structType, ok := typeSpec.Type.(*ast.StructType)
        if !ok {
                continue
        }
}

構造体名は取れた. 次はフィールド. structType.Fields.Listに入っている.

for _, field := range structType.Fields.List {
    // ``の部分はTag. 両端の`も取れてしまうので中身だけ欲しい場合は次のようにする
    tagValue := field.Tag.Value[1 : len(field.Tag.Value)-1]
    // フィールドの型は1度ast.Identにしてから. 
    identType, ok := field.Type.(*ast.Ident)
    if !ok {
        continue
    }
    fieldName := field.Names[0].Name
    fieldType := identType.Name
}

これでシンプル構造体の定義から, なにかツール作れそう.

困っています困っています 2016/07/19 18:33 はじめまして。ググッたらお詳しそうなので質問させて頂きます。

OS Android 4.1.1のタブレットなのですが

液晶が割れてしまい中身をそのまま同機種のタブレットに積み替えましたところ

タブレットの画面が日本語でRTL(Right-to-Left)言語アラビア語ヘブライ語
の向き いわゆるミラー反転向きになってしまいました。

adbで書き換える場所がわかる方教えて頂けませんか?

当方ずぶの素人でアプリを開発できる方尊敬しています。

もし宜しければ上記の件ご教授頂けましたら幸いですm(_ _)m

宜しくお願いいたします。

トラックバック - http://d.hatena.ne.jp/fkm/20150908

2015-04-04 ARC Welderを試してみた

[]ARC Welderを試してみた ARC Welderを試してみたを含むブックマーク

ARC Welderが出たので試してみた. Chrome appとしていれるのでChrome必要.

手元のアプリapkをいれてみた. おー, 普通に動くぞ. エミュレータよりサクサク.

f:id:fkm:20150404230246p:image

インストールすると, Chrome appの1つとして見える.

f:id:fkm:20150404230247p:image

GCMがまだだったり, OpenGLが動かないとかあるみたいだけど, 普通に作ったアプリなら普通に動くあたりがすごい

追記:GCMGCM for Chrome経由でどうもいけるっぽい

トラックバック - http://d.hatena.ne.jp/fkm/20150404

2015-03-05 Goのmailgunクライアント

[][]Goのmailgunクライアント Goのmailgunクライアントを含むブックマーク

mailgunというサービスがあります. ドメインもっていればTXTレコードとCNAMEを追加するだけで, 無料で10000通/日 メールが送れます(持ってない場合はmailgunが1つ送信用のをくれます)

これをGoで叩きたかったのでクライアントライブラリ書いてみました. 後から本家でも公開されてるのを知りましたが

場所はここ. ホント会社技術ブログを用意して, そこでお知らせするのがいいのですが...

使い方

1. go getでとってくる

$ go get github.com/mokelab-go/mail

2. クライアントオブジェクトを作って, Send()を呼ぶだけ.

package main

import (
    "fmt"
    "github.com/mokelab-go/mail/mailgun"
)

const (
    apiKey  = "<Input your API Key>"
    domain  = "<Input your domain in mailgun>"
    from    = "<Input from address>"
    to      = "<Input to address>"
    subject = "メールガンから送信"
    body    = "テストコードから本文"
)

func main() {
    client := mailgun.New(apiKey, domain, from)
    err := client.Send(to, subject, body)
    if err != nil {
        fmt.Printf("Unexepcted Error : %s", err)
    }
}

しんぷる

トラックバック - http://d.hatena.ne.jp/fkm/20150305

2015-02-12 Goのtype

[][]Goのtypeで遊ぶ Goのtypeで遊ぶを含むブックマーク

こんな関数があったとする.

func GetById(userId string) User {
}

引数文字列なので, 間違ってオブジェクトIDを入れてしまうかもしれない. そしてそれはコンパイル時にはわからない.

なので, UserIDという型を用意して, 間違いを防ごうと考えた.

package user
type UserID interface {
    // stringとして取り出せるようにする
    String() string
}

package impl
func GetById(userId user.UserID) User {
}

interfaceだと実際に使う時は実装必要なので, Javaとかだったらこんな風にImplクラスを作るのかな?

package impl
type UserIDImpl struct {
    value string
}
func (u *UserIDImpl) String() string {
    return u.value
}

func GetById(userId user.UserID) User {
}

// 呼び出し側. idはstring型
user := GetById(&impl.UserIDImpl{ value: id})

Goだとstringに別名を付けれるので, こう書ける.

package impl

type UserID string
func (u *UserID) String() string {
    // キャスト
    return string(u)
}

func GetById(userId user.UserID) User {
}

// 呼び出し側. idはstring型
user := GetById(impl.UserID(id))

呼び出し元でUserID(id)のようにキャスト必要なのが面倒か?

トラックバック - http://d.hatena.ne.jp/fkm/20150212

2015-02-05 SQLite3の型あれこれ

[]SQLite3の型とはいったい SQLite3の型とはいったいを含むブックマーク

Android SDKにSQLite3が実は付属してるので遊んでみた.

platform-toolsの中に入っている.

$ cd $ANDROID_HOME/platform-tools
$ ./sqlite3
SQLite version 3.8.6 2014-08-15 11:46:33
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite>

さっそくテーブルを作ってみる. in-memory databaseなので気軽に作って消せるのいいね.

sqlite> create table user(name text, age integer);
sqlite> .fullschema
CREATE TABLE user(name text, age integer);
/* No STAT tables available */
sqlite>

続いてレコードをいれてみる. レコード追加はinsert文ですよね.

sqlite> insert into user(name, age) values('fkm', 30);
sqlite> insert into user(name, age) values('moke', 1);

おっと手がすべった

sqlite> insert into user(name, age) values('fkm', 'fkm');
sqlite>

あれ, エラーにならないぞ?select文を発行してみる.

sqlite> .mode column
sqlite> .header on
sqlite> select * from user;
name        age
----------  ----------
fkm         30
moke        1
fkm         fkm
sqlite>

integerにしたはずのage列にfkmが入ってる。。

型を調べてみよう.

sqlite> select typeof(name), name, typeof(age), age from user;
typeof(name)  name        typeof(age)  age
------------  ----------  -----------  ----------
text          fkm         integer      30
text          moke        integer      1
text          fkm         text         fkm
sqlite>

型の指定無視される?と感じなくもないので, もうすこし調査。次のような行をinsert

sqlite> insert into user(name, age) values(1, '1');
sqlite>

型を見てみよう

sqlite> select typeof(name), name, typeof(age), age from user;
typeof(name)  name        typeof(age)  age
------------  ----------  -----------  ----------
text          fkm         integer      30
text          moke        integer      1
text          fkm         text         fkm
text          1           integer      1

TEXTだと数値をいれてもテキストに, 逆にINTEGERで文字列の1をいれるとintegerになる.

[追記]型の制約を付けるには?

テーブルを作る時にcheckを付けておくと, insert時にエラーにできる.

sqlite> create table user(name text, age integer, check(typeof(age) = 'integer'))
sqlite> insert into user(name, age) values('fkm', 1);
sqlite> insert into user(name, age) values('fkm', 'fkm');
Error: CHECK constraint failed: user
sqlite>
トラックバック - http://d.hatena.ne.jp/fkm/20150205