やりたいのは、 net/http の http.Header を拡張してメソッドを足したかった。
ちなみに http.Header は以下の定義になっている。
var http.Header map[string][]string
type の再定義
こんな感じにメソッドを追加したい。
package main
import (
"fmt"
"net/http"
)
// MyHeader 型を定義
type MyHeader http.Header
// X- を付けるメソッドを付ける
func (mh MyHeader) AddWithPrefix(name, value string) {
name = "X-" + name
mh.Add(name, value) // can't call http.Header#Add
}
func main() {
mh := MyHeader{}
name, value := "Hello", "World"
mh.AddWithPrefix(name, value)
}
これだと、以下のエラーが出る。
mh.Add undefined (type MyHeader has no field or method Add)
http://golang.org/ref/spec#Type_declarations によると
The declared type does not inherit any methods bound to the existing type, but the method set of an interface type or of elements of a composite type remains unchanged:
ということで、 http.Header#Add() が無い。どうするか。
Cast してしまう
メソッドの中で、もとの型にキャストしてしまうと、一応呼べる。
func (mh MyHeader) AddWithPrefix(name, value string) {
name = "X-" + name
http.Header(mh).Add(name, value) // can't call http.Header#Add
}
しかし、これだと MyHeader に対して http.Header のメソッドを呼ぶのに、
毎回キャストが必要。
mixin
型を定義して mixin(?) する。
// struct に mixin する。
type MyHeader struct {
http.Header
}
// そこにメソッドを加える
func (mh MyHeader) AddWithPrefix(name, value string) {
name = "X-" + name
mh.Add(name, value)
}
func main() {
mh := MyHeader{http.Header{}}
name, value := "Hello", "World"
mh.AddWithPrefix(name, value)
fmt.Println(mh)
}
これで呼べる。
range
ってところまではわかってたんだけど、問題は 2 つめの方法は
range が呼べないと思っていた。
つまり、 http.Header でできた以下ができない。
for name, value := range mh {
fmt.Println(name, value) // cannot range over mh (type MyHeader)
}
これができないと、 http.Header 使ってた部分を書き換えられないなと思っていた。
しかし、 http://golang.org/ref/spec#Struct_types に書かれているように
"Promoted fields act like ordinary fields of a struct"
なので、実は以下のようにすると range できる。
for name, value := range mh.Header {
fmt.Println(name, value)
}