質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Q&A

解決済

1回答

1257閲覧

typeを返すメソッドの値を変更すると、なぜ親の値が変更されるのか?

shi_ue

総合スコア4437

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

0グッド

0クリップ

投稿2017/07/02 07:58

編集2017/07/03 00:20

Goを勉強中です。c#以来の久しぶりのコンパイル言語にワクワクします。
「 A Tour of Go 」を一通りやって、何となく分かったような分からないような。

net/httpの練習でもしようと思い、Hello world!サーバーをやったので、次にJSONを返す、簡単なウェブサーバーを作ってみようと思い立ちました。

それで、まずヘッダーをContent-type: application/json; charset=utf-8に変えたいと思って探してみると、公式にサンプルがあります。それを元に簡単なコードを書きました。

go

1package main 2 3import ( 4 "net/http" 5 "fmt" 6) 7 8func main() { 9 http.HandleFunc("/test.json", 10 func(w http.ResponseWriter, r *http.Request) { 11 fmt.Printf("URL is %s\n", r.URL.String()) 12 w.Header().Set("Content-type:","application/json; charset=utf-8") 13 fmt.Fprintf(w, "{result: true}") 14 }, 15 ) 16 http.ListenAndServe(":8080", nil) 17} 18```ここで躓きました。 19 20[http.ResponseWriter](https://golang.org/pkg/net/http/#ResponseWriter)の`Header()`で返されるのが`Header`構造体であって、`*Header`というポインターではないのに、`w.Header().Set()`とヘッダーをセットしてあげると、ちゃんと親の`w`にも伝播するのは何故でしょうか? 21 22そもそも構造体&インターフェースが良く分かってないので、トンチンカンな質問かもしれませんが、Goに詳しい方々、何が起きているのか説明していただけないでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

Header は構造体ではないです。

type Header map[string][]string

map の別名です。なのでポインタとして扱われます。

ちなみに余談ですが、なぜ ResponseWriter#Header() がフィールド直参照ではなく関数呼び出しなのかという豆知識。

実は昔、ResponseWriter#Header は ResponseWriter のフィールド(map[string][]string)でした。しかしユーザコードの中で好き勝手触れてしまい、ヘッダの値の中で改行を出力出来てしまったり、nil を突っ込めてしまったり、色々と問題が発生しました。そこで外部からは直接ヘッダを操作せずにメソッドを使って操作するのを標準の動作と見える様に Header は関数に変わりました。

投稿2017/07/03 00:54

mattn

総合スコア5030

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shi_ue

2017/07/03 01:00

なるほど!map自体を指すとポインタですよね。勘違いしてました。 豆知識もためになりました!Goも変遷してるんですね。
shi_ue

2017/07/03 01:38

配列・スライスは値渡し、mapはポインタ渡し、なんですね。 ちょっとCの考え方とは違う感じで頭を切り替えないとですね。
mattn

2017/07/03 01:53

配列、スライスも参照渡しですね。 https://play.golang.org/p/Zh2ZcH1aVT 一般的な言語と異なるもので躓きやすいのが string ですかね。nil 入らないので。
shi_ue

2017/07/03 11:13

配列は値渡しみたいです。 https://play.golang.org/p/Vot-DDI-RU 関数に渡す前後で値が変わりません。関数で受け取った配列はアドレスが変わってます。 スライスは参照渡しなんですね。 スライスの場合、appendを使うと、使ったその場で新たなスライスが作られてしまうので、違うスライスになってしまい、関数の終わりで破棄されてしまうみたいです。 ただ、興味深いのは、capを設定したスライスにappendすると同じアドレスのスライスを使うのに、関数の終わりに追加分を破棄?します。 https://play.golang.org/p/QzxlNzqr9- appendしたければ、ポインタにしろ、ってことなんですかね? 長々とお付き合いいただき、ありがとうござました。 勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問