LoginSignup
12
12

More than 5 years have passed since last update.

map をベースとした type の拡張 #golangjp

Posted at

やりたいのは、 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)
}
12
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
12