YAMAGUCHI::weblog

噛み付き地蔵に憧れて、この神の世界にやってきました。マドンナみたいな男の子、コッペです。

「逆引きGolang」で気になったところ

はじめに

こんにちは、タゾチャイティーラテです。最近急に蒸し暑くなったり、寒かったり中途半端な天気が多いですね。逆引きGolang というサイトが公開されてて面白いなあと思って見てたんですが、僕だったらこう書くなというものがいくつかあったので覚書きです。

文字列

部分文字列を置き換える

これは無理に strings 使わないほうが楽なんじゃないかと思いますがどうでしょう。自分で関数定義するのは面倒かもしれませんが。

package main

import "fmt"

func main() {
    s := "Apple Banana Orange"
    r1 := replace(0, 5, []rune(s), []rune("Vine"))
    fmt.Println(string(r1))
    r2 := replace(5, 6, r1, []rune("Lemon"))
    fmt.Println(string(r2))
}

func replace(start, length int, orig, target []rune) []rune {
    ret := make([]rune, len(orig)+len(target)-length)
    copy(ret, orig[0:start])
    copy(ret[start:], target)
    copy(ret[start+len(target):], orig[start+length:])
    return ret
}

16進文字列を整数に変換する

コメントに "0xを含んではいけない" とありますが、含んでも大丈夫です。その場合はbaseを0にします。baseを0にした場合は文字列の見て0が先頭にあれば8進数、0xであれば16進数と判断します。

package main

import (
    "fmt"
    "strconv"
)

func main() {
    s := "0xff"
    sh, _ := strconv.ParseInt(s, 0, 64)
    fmt.Println(sh)
}

漢字コードを変換する

たぶん書きかけなんだろうけど、直接 EUCJP は呼べないので japanese.EUCJP.NewEncoder() としないと動かない。

日付と時刻

これは別に本文と関係ないけど、 time パッケージにはRFCとかで定義されてるフォーマットは定数で事前定義されてるっていうのをFYI。

const (
        ANSIC       = "Mon Jan _2 15:04:05 2006"
        UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
        RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
        RFC822      = "02 Jan 06 15:04 MST"
        RFC822Z     = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
        RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
        RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
        RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
        RFC3339     = "2006-01-02T15:04:05Z07:00"
        RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
        Kitchen     = "3:04PM"
        // Handy time stamps.
        Stamp      = "Jan _2 15:04:05"
        StampMilli = "Jan _2 15:04:05.000"
        StampMicro = "Jan _2 15:04:05.000000"
        StampNano  = "Jan _2 15:04:05.000000000"
)

配列

配列に要素を追加する

append 使えばいいんですが、あんまり回数が多いと効率が悪いので、長さがわかってるならばバッファを確保したほうがよいと思う。

一致する要素を全て取り除く

まず全然関係ないけど、全体的にアンダースコア区切りの関数名がよく見られるけど、Goの慣習的には変数名も関数名もキャメルケースです。詳しくは ここ 参照。あと複数パッケージimportするときは括弧で囲ったほうが読みやすいかなあ。

deleteStrings()はまっすぐ書いたほうがスッキリ書けそう。

package main

import "fmt"

func main() {
    a := []string{"apple", "orange", "lemon", "apple", "vine"}

    str, a, err := deleteStrings(a, "apple")
    fmt.Println(str) // => "apple"
    fmt.Println(a)   // => "[orange lemon vine]"
    fmt.Println(err) // => "<nil>"

    str, a, err = deleteStrings(a, "apple")
    fmt.Println(str) // => ""
    fmt.Println(a)   // => "[orange lemon vine]"
    fmt.Println(err) // => "Couldn't find"
}

func deleteStrings(slice []string, s string) (string, []string, error) {
    ret := make([]string, len(slice))
    i := 0
    for _, x := range slice {
        if s != x {
            ret[i] = x
            i++
        }
    }
    if len(ret[:i]) == len(slice) {
        return "", slice, fmt.Errorf("Couldn't find")
    }
    return s, ret[:i], nil
}

おわりに

公式ドキュメントでは文法などはわかりやすく書いてあって、あのサイトだけひと通り読んでれば普通に書けるようになるのですが、やはり逆引き的にスニペットがあると便利ですね。これからも更新頑張ってください。