From 428a916c61b5029898fd0eb3bdb78c0c2d5f5716 Mon Sep 17 00:00:00 2001 From: devlights Date: Tue, 5 Dec 2023 03:08:14 +0000 Subject: [PATCH] Add strings.Clone example --- examples/basic/strs/README.md | 1 + examples/basic/strs/examples.go | 1 + examples/basic/strs/using_strings_clone.go | 76 ++++++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 examples/basic/strs/using_strings_clone.go diff --git a/examples/basic/strs/README.md b/examples/basic/strs/README.md index 8219d3e7..eb60cac1 100644 --- a/examples/basic/strs/README.md +++ b/examples/basic/strs/README.md @@ -11,3 +11,4 @@ |using\_builder.go|string\_using\_builder|strings.Builder を利用したサンプルです.| |rune\_count.go|string\_rune\_count|utf8.RuneCountInString() のサンプルです.| |diff\_trimright\_trimsuffix.go|string\_diff\_trimright\_trimsuffix|strings.TrimRight と strings.TrimSuffix のちょっとした違いについてのサンプルです.| +|using\_string\_clone.go|string\_using\_clone|Go 1.18 で追加された strings.Clone() のサンプルです| diff --git a/examples/basic/strs/examples.go b/examples/basic/strs/examples.go index 1b0f163d..d8630180 100644 --- a/examples/basic/strs/examples.go +++ b/examples/basic/strs/examples.go @@ -21,4 +21,5 @@ func (r *register) Regist(m mapping.ExampleMapping) { m["string_rune_count"] = RuneCount m["string_diff_trimright_trimsuffix"] = DiffTrimRightAndTrimSuffix m["string_cut_prefix_suffix"] = CutPrefixSuffix + m["string_using_clone"] = UsingStringsClone } diff --git a/examples/basic/strs/using_strings_clone.go b/examples/basic/strs/using_strings_clone.go new file mode 100644 index 00000000..0c108bdc --- /dev/null +++ b/examples/basic/strs/using_strings_clone.go @@ -0,0 +1,76 @@ +package strs + +import ( + "os/exec" + "strings" + + "github.com/devlights/gomy/output" +) + +// UsingStringsClone は、Go 1.18 で追加された strings.Clone() のサンプルです。 +// +// # REFERENCES +// - https://pkg.go.dev/strings@go1.21.4#Clone +func UsingStringsClone() error { + // + // strings.Clone() は、Go 1.18 で追加された関数。 + // 新たなメモリ割り当ても行われるので、ディープコピーされるイメージ。 + // 部分文字列を特定のストアに対して保持するようなシチュエーションで利用できる。 + // (Goの標準コンパイラでは、現状元の文字列と部分文字列は同じメモリを共有するようになっているため + // 数が多い、または、文字列のサイズが巨大な場合などにディープコピーしておかないとメモリが残ることなる) + // + + const ( + NUM_ITEMS = 100 + ) + + var ( + l = make([]string, NUM_ITEMS) + ) + + // 1024バイトのランダム文字列を1000個用意 + for i := 0; i < NUM_ITEMS; i++ { + var ( + c *exec.Cmd + output []byte + err error + ) + + c = exec.Command("/bin/bash", "-c", "openssl rand -base64 1024 | tr -d '\n'") + if output, err = c.Output(); err != nil { + return err + } + + l[i] = string(output) + } + + // + // 各文字列の先頭5文字分を識別子として保持しておく仕様があるとする + // + + var ( + store1 = make([]string, NUM_ITEMS) + store2 = make([]string, NUM_ITEMS) + ) + + // 部分文字列を取り出し、そのまま保持 + // この場合、元文字列と部分文字列は同じメモリを共有している可能性があるため + // 場合によっては、5バイト分だけじゃなく、文字列全部がメモリに残ったままとなる + for i := 0; i < NUM_ITEMS; i++ { + store1[i] = l[i][:5] + } + + // 部分文字列を取り出し、クローンしてから保持 + // Go 1.18 で追加された strings.Clone() を利用することで、新たな割当が行われた状態で + // 文字列がクローンされる。なので元文字列全部がメモリに残ることはなくなる + for i := 0; i < NUM_ITEMS; i++ { + store2[i] = strings.Clone(l[i][:5]) + } + + for i := 0; i < 3; i++ { + output.Stdoutf("[store1]", "%d: %s\n", i, store1[i]) + output.Stdoutf("[store2]", "%d: %s\n", i, store2[i]) + } + + return nil +}