読者です 読者をやめる 読者になる 読者になる

i++

プログラム系のメモ書きなど

golang : eval (数式の evaluation)を行う

golang

go/token パッケージ、go/types パッケージ、go/constant パッケージを使用します。

import (
    "fmt"
    "go/token"
    "go/types"
    "go/constant"
)

fs := token.NewFileSet()
tv, err := types.Eval(fs, nil, token.NoPos, "1 + 2 * 3 % 4")
if err != nil {
    fmt.Println(err)
    return
}
val, ok := constant.Int64Val(tv.Value)
if !ok {
    fmt.Println("Failed to get Int64Val")
    return
}
fmt.Println(val)

// 結果は 3。

(Go 言語で プログラマ脳を鍛える数学パズル シンプルで高速なコードが書けるようになる70問 をトライ中に 2問目を解くために方法を探しただけで、中身はあまりよくわかっていません。)

Angular2 : [ts] Property 'map' does not exist on type 'Observable<Response>'

Angular TypeScript

http.get(url).map(...) を試みたところ発生。

[ts] Property 'map' does not exist on type 'Observable<Response>'

import rxjs/add/operator/map を追加することで解決。

import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';

catch には import 'rxjs/add/operator/catch'; が必要になる。 一括でインポートするには import 'rxjs/Rx';

golang : template の range で index を使う

golang

以下の様なデータを template.Execute のデータに渡したとすると

type data struct {
    Values      []string
    OtherValues []string
}

テンプレートで

<ul>
    {{range $i, $v := .Values}}
    <li>{{index $.OtherValues $i}} のようにするとインデックスでアクセスできる( OtherValues[i]の値)。{{$v}} はもちろん Values[i]</li>
    {{end}}
</ul>

のようにすれば、Values にループをかけている最中にインデックスを使って他の配列やスライスの特定の値にアクセスできる

template - The Go Programming Language に書いている通り、テンプレート中の {{index スライスや配列の変数 インデックス値}}ソースコード中のスライスや配列の変数[インデックス値] に対応する。

index
    Returns the result of indexing its first argument by the
    following arguments. Thus "index x 1 2 3" is, in Go syntax,
    x[1][2][3]. Each indexed item must be a map, slice, or array.

また、$ が Execution に渡されたデータを指すので、range 中にデータの他の変数にアクセスするには $.変数名 となる。

golang : コミット時に gofmt を実行する(pre-commit hook)

golang

misc/git/pre-commit - The Go Programming Language を参考に作成しました。

オリジナルではフォーマットされていないコードがある場合にコミットを中断していますが、以下のスクリプトでは gofmt を実行して git add するところまでやっています。

#!/bin/sh

gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '.go$')
[ -z "$gofiles" ] && exit 0

unformatted=$(gofmt -l $gofiles)
[ -z "$unformatted" ] && exit 0

echo >&2 "Info: Running gofmt as some Go files are not formatted with gofmt."
for fn in $unformatted; do
    gofmt.exe -s -w $fn
    echo >&2 "gofmt -s -w $fn"
    git add $fn
done

exit 0

リンク先は、gofmt に加えて、gocyclo によるCyclomatic complexity のチェック(見るだけ)と goimports の実行も合わせたものになります。

github.com

Google App Engine : appcfg.py update 時の HTTP Error 403: Forbidden Unexpected HTTP status 403.

Google App Engine

エラーの全文は以下の通り。

久々に GAE のプロジェクトを作成してデプロイしようと思ったら発生しました。

python appcfg.py -A YOUR_APP_ID -V v1 update src/
06:44 PM Application: YOUR_APP_ID (was: None); version: v1 (was: None)
06:44 PM Host: appengine.google.com
06:44 PM Starting update of app: YOUR_APP_ID, version: v1
06:44 PM Getting current resource limits.
2016-04-23 18:44:08,184 ERROR appcfg.py:2402 An error occurred processing file '': HTTP Error 403: Forbidden Unexpected HTTP status 403. Aborting.
Error 403: --- begin server output ---
You do not have permission to modify this app (app_id=u's~YOUR_APP_ID').
--- end server output ---

python - Google App Engine app deployment - Stack Overflow に書かれている通り、%ユーザディレクトリ%/.appcfg_oauth2_tokens を削除してから再実行することで、ブラウザで認証画面が開いてアップロードできました。

golang : URL短縮サービス goo.gl を使う

golang

URL Shortener API の使い方はこちら → URL Shortener

ここでは API Key を使った方法を載せています。

type responseParam struct {
    Kind    string `json:"kind"`
    Id      string `json:"id"`
    LongUrl string `json:"longUrl"`
}

func GetShortenedUrlImpl(longUrl string) (string, error) {

    values := url.Values{}
    values.Add("key", GoogleApiKey) // パッケージの変数として定義し、この関数を呼ぶ前にセットしておきます。

    url := "https://www.googleapis.com/urlshortener/v1/url" + "?" + values.Encode()

    param := fmt.Sprintf(`{"longUrl":"%s"}`, longUrl);
    req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(param)))
    if err != nil {
        return "", err
    }
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return "", err
    }
    defer resp.Body.Close()
    respBody, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return "", err
    }
    var respParam responseParam
    err = json.Unmarshal(respBody, &respParam)
    if err != nil {
        return "", err
    }
    return respParam.Id, nil
}

golang : 日本語(マルチバイト)文字を含む string の substring

golang

go では string のスライスは byte として扱われるので、日本語のようにマルチバイト文字を含んだ文字列 str に対して str[start:start+length] のようなことをすると、思わぬ場所が切り取られてしまいます。

この問題を回避するために、一旦 rune にキャストしてから string に戻します。

func substring(str string, start, length int) string {
    if start < 0 || length <= 0 {
        // 明らかに不正な値なので、チェックせずに進んで panic を起こしても良さそうです。
        return str
    }
    r := []rune(str)
    if start + length > len(r) {
        return string(r[start:])
    } else {
        return string(r[start:start + length])
    }
}