使うたんびに毎回「あれ…」ってなってplaygroundで確認しなおす個人的事項をここに
でもどうせまた次も忘れて確認すんだろうな…
slice操作
https://github.com/golang/go/wiki/SliceTricks
大体ここで困らない
rand.Intn
0..引数で渡した値「未満」の値になります。関数のコメントに0..n
って書いてあるからそりゃそうなんですが、..n
はn未満で...n
はn以下って割と忘れそうになる表現。
rand.Seed(time.Now().UnixNano())
for i := 0; i < 10; i++ {
fmt.Println(rand.Intn(2)) // 0 or 1
}
空文字をsplit
rubyだと空文字をsplitすると空配列が返りますが、golangは先頭の要素が空文字である1要素のsliceが返ります
str := ""
result := strings.Split(str, "@")
fmt.Println(result) // => []
fmt.Println(len(result)) // => 1
if result[0] == "" {
fmt.Println("yes empty") // 出力される
}
HTTP/HTTPS URLパース関連
ParseとParseRequestURI
実装見ればすぐですが、両方ともparse
って関数でバラすことには変わりありません。
違いはParseのほうはハッシュマークの面倒を見てくれることしかないように思います。
url := `http://test.com/path#hashmark`
parsed, _ := netu.ParseRequestURI(url)
fmt.Println(parsed.Fragment) // => empty
parsed, _ = netu.Parse(url)
fmt.Println(parsed.Fragment) // => hashmark
デコード
net/url
パッケージのParse/ParseRequestURI共に、デコードまで面倒見てくれます。
QueryUnescapeを通したあとのURLを放り込むと二重にデコードしちゃう形になるので気を付けましょう。
例えば文字列としてプラス記号とか混ざってた場合、空白になってしまって悲しみを背負います。
なお、netu
はnet/url
に与えてるエイリアスです そのまんまだとurlって変数名とかぶるんで…
url := `http://test.com?param=%E3%81%82%E3%81%82%2B%E3%81%82`
parsed, err := netu.ParseRequestURI(url)
fmt.Println(err) // => nil
fmt.Println(parsed.Query()) // => map[param:[ああ+あ]]
decoded, err := netu.QueryUnescape(url)
fmt.Println(err)
parsed, _ = netu.ParseRequestURI(decoded)
fmt.Println(parsed.Query()) // => map[param:[ああ あ]] 二重にデコードされる
QueryUnescapeに失敗するパラメータが含まれているURLをパースしようとした場合
爽やかに通ります。基本的にURLとして成立してさえいれば彼らは怯まないようです。
url := `http://test.com/?param=%%%&a=b`
parsed, err := netu.ParseRequestURI(url)
fmt.Println(err) // => nil
fmt.Println(parsed.Path) // => /
fmt.Println(parsed.Host) // => test.com
fmt.Println(parsed.Query()) // => map[a:[b]]
_, err = netu.QueryUnescape(url)
fmt.Println(err) // => invalid URL escape "%%%"
Schemaが省略されている場合
//aaa.com
のような形式ですね。エラーとはなりませんがあまり喜ばしい結果でもありません。
url := `//test.com/?param=%E3%81%82%E3%81%82%2B%E3%81%82`
parsed, err := netu.ParseRequestURI(url)
fmt.Println(err) // => nil)
fmt.Println(parsed.Path) // => //test.com/
fmt.Println(parsed.Host) // => empty
fmt.Println(parsed.Query()) // => map[param:[ああ+あ]]
decoded, err := netu.QueryUnescape(url)
fmt.Println(decoded) // => //test.com/?param=ああ+あ
fmt.Println(err) // => nil
ちょっとアレですが、パースしてSchemaが空だったら勝手に補完してもう1回パースする、とかでお茶を濁してます。
文字列置換
regexpで無くてもなんとかなる単純な置換だが、置換候補が複数あるような場合、strings.Replaceを連発するのはちょっとねって時にはstrings.NewReplacerが使えます。
str := "yesNOyeahBAR"
rep := strings.NewReplacer("yes", "NO", "yeah", "BAR")
a := rep.Replace(str)
fmt.Println(a) // => NONOBARBAR
str = "yesNOyeahBAR"
rep = strings.NewReplacer("yes", "NO", "yeah", "BAR", "NO", "AHHH")
a = rep.Replace(str)
fmt.Println(a) // => NOAHHHBARBAR
下は「まさか単純に左から順番に解決してるんじゃなかろうな…」って一瞬思ってしまったので念のために確認してるやつです。
うっかり無限ループとか流石に笑えない
部分配列
sliceの仕様をちゃんと理解しろっつう話なんですが
a := []int64{1, 2, 3}
fmt.Println(a[0:]) // => [1 2 3]
fmt.Println(a[:]) // => [1 2 3]
fmt.Println(a[:3]) // => [1 2 3]
fmt.Println(a[0:3]) // => [1 2 3]
fmt.Println(a[1:2]) // => [2]
fmt.Println(a[0:0]) // => []
これはまあ問題ないと思います。
n:aで、nを省略すれば0、aを省略すればlen
nは始点indexを表し、始点そのものも要素に含む
aは始点からの個数
と考えればまあ特に矛盾はしないように思います。が、
コメ指摘があったんで確認しなおしたらaは個数ではないですね。
1...len(index+1)と思えば良いか。
a := []int64{1, 2, 3}
fmt.Println(a[3:3]) // => [] ???
fmt.Println(a[4:]) // => panic
fmt.Println(a[3:4]) // => panic
fmt.Println(a[3]) // => panic
なんで1番上がpanicしないんだ…実務上困ることは無さそうだけど謎…