Goツアーには、チャンネル用の次の例があります。 https://tour.golang.org/concurrency/2
package main
import "fmt"
func sum(a []int, c chan int) {
sum := 0
for _, v := range a {
sum += v
}
c <- sum // send sum to c
}
func main() {
a := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(a[:len(a)/2], c)
go sum(a[len(a)/2:], c)
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y)
}
チャネルcはsum関数で変更され、関数が終了した後も変更は持続します。明らかにcは参照渡しされましたが、cへのポインタは作成されませんでした。 goの参照により、チャネルは暗黙的に渡されますか?
技術的にはコピーされます。make
を使用すると、ヒープに何かを割り当てているため、技術的には背後のポインターになります。しかし、ポインタ型は公開されていないため、参照型と考えることができます。
[〜#〜] edit [〜#〜]:仕様から:
組み込み関数makeは、タイプTを取ります。これは、スライス、マップ、またはチャネルタイプでなければならず、オプションでタイプ固有の式のリストが続きます。タイプT(* Tではない)の値を返します。メモリは、初期値のセクションで説明されているように初期化されます。
チャネルは、使用する前に初期化する必要があります。 Makeはこれを行うため、参照型として使用できます。
これが基本的に意味することは、それを関数に渡して、そこから読み書きできることです。一般的な経験則は、make
、new
、または&
、基になるデータをコピーせずに別の関数に渡すことができます。
したがって、以下は「参照」タイプです。
関数に渡すときは、データ型(数値、ブール、構造体など)のみがコピーされます。文字列は不変ですが、値渡しではないため、特別です。これは、以下が期待どおりに機能しないことを意味します。
type A struct {
b int
}
func f(a A) {
a.b = 3
}
func main() {
s := A{}
f(s)
println(s.b) // prints 0
}
Goのすべては、値によって渡され、割り当てられます。チャネルタイプやマップタイプなどの特定の組み込みタイプは、非表示の内部構造への不透明なポインターとして動作します。また、チャネルまたはマップに対する操作により、その内部構造を変更することができます。これらは、nil
ポインターに似たnil
から始まります。
「はい」と言うこともできますが、「チャネルcは合計関数で変更されます」と言うのは、実際には正しい用語ではありません。チャネルの送受信は、実際には変更とは見なされません。
スライスとマップは同じように動作することに注意してください。詳細については http://golang.org/doc/effective_go.html をご覧ください。
また、「参照渡し」は、c
内のsum
に割り当てを行って、sum以外の値(基になるデータではなく)を変更できることを意味しますが、そうではありません。
チャネル変数は参照ですが、「参照」の定義に依存します。 言語仕様 参照型に言及することはありません。
sum
関数で「変更」されるチャネル(変数)はありません。チャンネルに送信すると、状態が変わります。
言い換えれば、はい、チャネルは実行時構造へのポインタとして実装されます。参照セマンティクスには厳密に必要なことに注意してください。
編集:上記の文は、「参照セマンティクスに厳密に必要なnotであることに注意してください。」、つまり「ない」という言葉はMIAに行きました。最終的に作成された混乱のためにすみません。