空文字列確認は長さをとるべきか?

TL;DR s == ""とlen(s) == 0は等価 文字列比較か、長さ比較か Go言語で文字列が空かどうかを調べるには次の二つの方法があります。 1 2 3 4 5 6 7 8 9 // 1: 文字列を空文字列と比較する if s == "" { // do something } // 2: 文字列の長さが0かどうか調べる if len(s) == "" { // do something } 標準パッケージ・サードパーティパッケージともに、どちらの書き方も散見されます。 どちらを使うのが良いのでしょうか? 答えはどちらでも良いだそうです。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package benchmark_test import "testing" var somethingString = "hogehogefugafuga" func BenchmarkCompareString(b *testing....

2019-10-09 · nasa9084

array/sliceに対する存在確認関数のベンチマーク

Pythonでいうところの、次の様な条件式を実現する関数を書きたかった。 1 2 3 4 5 ls = ["foo", "bar", "baz"] s = "baz" if s in ls: print("FOOBAR!") 対象がリストの時、普段なら普通にfor文を回すのですが、今回やりたかったのは定数値の一覧にあるかどうか、だったのと、定数の数も少なかったので、とりあえずで以下の様に実装していました。 1 2 3 4 5 func something(s string) error { if s != "foo" && s != "bar" && s != "baz" { return errors.New("value invalid") } } 流石に雑すぎるので、リファクタリングしよう、と思ったのですが、「はて、for文挟んだら遅くなったりしないだろうか」などと考えてしまったのでベンチマークを取りました。 TL; DR 素直にfor文を回しても大して問題はなさそう result 今回取ったベンチマークは6種類です。 for-range文を回す for文を回す map[string]struct{}を集合として取り扱ってみる &&, ||でつなぐ switch文を使う sort.SearchStrings()を使う 6番目のsort.SearchStrings()を使う方法はstackoverflow に書いてあった方法で、二分探索をしてくれるというのでやってみました。 結果は次の通り。 BenchmarkInByForRange-4 200000000 9.34 ns/op 0 B/op 0 allocs/op BenchmarkInByFor-4 100000000 10....

2018-06-26 · nasa9084

strings.Builderとbytes.BufferのWrite系関数のベンチマーク

TL; DR 平均して見るとstrings.Builder#WriteXXXの方が速そう strings.Builder Go 1.10からstrings.Builder構造体が追加されました。 公式ドキュメントには、 A Builder is used to efficiently build a string using Write methods. It minimizes memory copying. The zero value is ready to use. Do not copy a non-zero Builder. と説明が書かれています。 おそらく、これまで文字列の組み立てをする際にはbytes.Bufferを使っている場合が多かったと思われますが、そういった目的の選択肢として作られたようです。 が、説明を読んでもいまいち違いがわかりません。 とりあえず、bytes.Bufferとstrings.Builderでは速度面で違いがあるのか調べるべく、ベンチマークを実施しました。 条件 実行した環境 MacBook Air MacOS Sierra 10.12.6 CPU: Core i7 1.7GHz メモリ: 8GB 実行する関数 Write WriteByte WriteRune WriteString exec 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 $ for i in {1....

2018-03-05 · nasa9084

Go言語で文字列を処理する

Go言語のregexpパッケージを使用した正規表現の処理は、一般的なスクリプト言語の処理速度と同程度で、正規表現を使用しない処理に比べてパフォーマンスがよくありません1。 そのため、可能であるならregexpパッケージを使用しないようにすべきです。 しかし、すべての処理を自分で書くのは大変です。 標準パッケージにも文字列を処理する関数が数多く用意されています。 strings パッケージ stringsパッケージはその名の通り、文字列を取り扱うパッケージです。 UTF-8でエンコードされた文字列(普通の文字列)をそのまま取り扱います。 判別系 Contains 1 func Contains(s, substr string) bool Contains関数は、sの中にsubstrが存在するかどうかを返します。 Pythonで言うところのsubstr in sに相当します。 正規表現ならば、substrとのmatchで真偽値をとることに相当します。 example 1 2 3 4 5 fmt.Println(strings.Contains("hogefugapiyo", "fuga")) // Output: true fmt.Println(strings.Contains("hogefugapiyo", "foo")) // Output: false ContainsAny 1 func ContainsAny(s, chars string) bool ContainsAny関数はsの中に、charsに含まれる文字のいずれかが存在するかどうかを返します。 つまり、charsは文字列ですが、扱いとしては文字の配列であると考えた方が良いでしょう。 正規表現で表すなら、/[${chars}]/の様な表現と考えられます(${chars}は置き換える)。 example 1 2 3 4 5 fmt.Println(strings.ContainsAny("hogefugapiyo", "abcd")) // Output: true fmt.Println(strings.ContainsAny("hogefugapiyo", "1234")) // Output: false HasPrefix 1 func HasPrefix(s, prefix string) bool HasPrefix関数は、sの頭がprefixと等しいかどうかを判別します。 正規表現で^を使った文字列マッチに相当します。...

2018-03-05 · nasa9084

テキストを列ごとにそろえて出力する

TL;DR: 標準パッケージtext/tabwriter を使用する コマンドラインツールで標準出力を良い感じにそろえて出力したい場合があります。 例えば、docker では、以下の様に出力されます。 1 2 3 4 $ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8caad461b4a4 redis "docker-entrypoint.s…" 5 days ago Up 5 days 0.0.0.0:6379->6379/tcp redis-svr 329c9f9be035 mysql "docker-entrypoint.s…" 5 days ago Up 5 days 0.0.0.0:3306->3306/tcp mysql-svr このような map、あるいは構造体の配列 の様なものを、きれいに表形式の様に列をそろえて出力したい場合に便利なのが標準パッケージのtext/tabwriter です。 その名の通り、タブ区切りの文字列を良い感じに出力してくれるパッケージです。 text/tabwriterで定義されているのはいくつかの設定用定数 と、Writer構造体 のみです。 Writerは(勿論)io.Writerインターフェース を実装しています。 使用方法は通常のio.Writerとはすこし変わっていて、最初にWriter.Init() で初期化し、任意回数Writer.Write() で書き込みをした後、Writer.Flush() で整形した文字列を出力します。 NewWriter() 関数はWriter構造体をnew()した後Init()するのと同等です。 Writer.Init()関数及びNewWriter()関数に与える引数は以下の様になっています。 名前 型 内容 output io.Writer Flush()したときの出力先 minwidth int 1セルあたりの最小幅(パディングを含む) tabwidth int タブ文字の幅(スペースの個数と等しい) padding int パディング1 padchar byte パディング文字2 flags int 調整用フラグ 最後の引数である、調整用フラグには0(標準状態)を与えるか、パッケージ定数 の論理和を用いて設定を与えます。...

2018-01-29 · nasa9084