Call-by-Value, for-range string, for-loop gives copy, Closure | Go日記
for-range で string をループすると byte ではなく rune を返す
s := "ありがとう"
for i, r := range s {
fmt.Println(i, r, string(r))
}
0 12354 あ
3 12426 り
6 12364 が
9 12392 と
12 12358 う
What we are seeing is special behavior from iterating over a string with a for-range loop. It iterates over the runes, not the bytes.
Bodner, Jon. Learning Go (p.118). O'Reilly Media. Kindle 版.
for ループはコピーを提供する
package main
import (
"fmt"
)
func main() {
vals := []string{"a", "b", "c"}
for _, v := range vals {
v = "X"
fmt.Println(v) // X
}
fmt.Println(vals) // [a b c]
}
Closure
package main
import (
"fmt"
)
func main() {
f := foo()
fmt.Println(f("John")) // Hi, John
fmt.Println(foo()("Papa")) // Hi, Papa
}
type r func(string) string
func foo() r {
foomt := "Hi, %v"
return func(s string) string {
return fmt.Sprintf(foomt, s)
}
}
foo の中で foomt 変数の値を無名関数の中に閉じ込めて、関数を値として返している。
また、r 型は関数の形を定義しているので、foo() の戻り値のアノテーションとして置ける。見た目がスッキリする。
Go is Call by Value
『Learning Go』5. Function, Go is Call by Value ~ 6. Pointers の前半から抜書き。
Go is Call-by-Value language.
It means that when we supply a variable for a parameter to a function,
Go always makes a copy of the value of the variable.
...
If a pointer is passed to a function.
The function gets a copy of the pointer.
This(the copy of the pointer) still points to the original data, which means that the original data can be modified by called function.
Go は関数への値を渡すとき Call-by-Value で一貫している言語。
ポインターの Value はなにかといえばアドレスである。
Go でポインターを渡すということは、呼ばれた関数の中でポインターの指す値が変更されることを明示的に示している。
ポインター引数があれば、それは「変更するぞ」という宣言なので、破壊的に変更されることを前提としてその関数を使用する。
関数を書くときにポインター引数を設置するならば、それはそのポインターの指すオリジナル値を変更するという意思表示とする。
Go の場合は、何を変更して、何を変更しないかを明示的に意図してコーディングしていく。ある変数がどの時点で生まれて、どのタイミングで変更され、どこで寿命が尽きるのかを見極める必要がある。Go はそれが見極められるような言語仕様になっている(と、今のところ感じる。実務で使いだして実感できるかはあとで検証する)。当然変数のスコープがでかくなると追いきれなくなる。変数の受け持つスコープの範囲も、より小さくなるように、もしくは、より単純になるように、見極めながらコーディングすることが重要。
Sample code:
SN
参考書籍
この記事が気に入ったらサポートをしてみませんか?