私はかなり新しいので、この notify パッケージで遊んでいました。
最初は、次のようなコードがありました。
func doit(w http.ResponseWriter, r *http.Request) {
notify.Post("my_event", "Hello World!")
fmt.Fprint(w, "+OK")
}
Hello World!
に改行を追加したかったのですが、上記の関数doit
には追加しませんでした。これはかなり簡単なことですが、その後のhandler
には次のようになります。
func handler(w http.ResponseWriter, r *http.Request) {
myEventChan := make(chan interface{})
notify.Start("my_event", myEventChan)
data := <-myEventChan
fmt.Fprint(w, data + "\n")
}
go run
の後:
$ go run lp.go
# command-line-arguments
./lp.go:15: invalid operation: data + "\n" (mismatched types interface {} and string)
グーグルで少し調べた後、私は SOに関するこの質問 を見つけました。
次に、コードを次のように更新しました。
func handler(w http.ResponseWriter, r *http.Request) {
myEventChan := make(chan interface{})
notify.Start("my_event", myEventChan)
data := <-myEventChan
s:= data.(string) + "\n"
fmt.Fprint(w, s)
}
これは私がやるべきことでしたか?コンパイラエラーがなくなったので、それはかなり良いと思いますか?これは効率的ですか?別のやり方でやるべきですか?
Go仕様 に従って:
インターフェイスタイプとタイプTの式xの場合、プライマリ式x。(T)は、xがnilではなく、xに格納されている値がタイプTであることをアサートします。
「タイプアサーション」を使用すると、インターフェイス値に特定の具象タイプが含まれていること、または具象タイプが別のインターフェースを満たすことを宣言できます。
あなたの例では、データ(type interface {})に具象型文字列があると断言していました。間違っていると、実行時にプログラムがパニックになります。効率について心配する必要はありません。チェックするには、2つのポインタ値を比較するだけです。
文字列かどうかわからない場合は、2つの戻り構文を使用してテストできます。
str, ok := data.(string)
データが文字列でない場合、okはfalseになります。そのようなステートメントを次のようなifステートメントにラップするのが一般的です。
if str, ok := data.(string); ok {
/* act on str */
} else {
/* not string */
}
これはgolangではtype assertion
として知られており、一般的な方法です。
goのツアー の説明を次に示します。
型アサーションは、インターフェイス値の基礎となる具体的な値へのアクセスを提供します。
t := i.(T)
このステートメントは、インターフェイス値iがconcrete typeTを保持していることを表明します。基になるT値を変数tに割り当てます。
IがTを保持していない場合、ステートメントはパニックを引き起こします。
インターフェイス値が特定の型を保持しているかどうかをテストするために、型アサーションは2つの値を返すことができます。基礎となる値と、アサーションが成功したかどうかを報告するブール値です。
t, ok := i.(T)
IがTを保持している場合、tは基になる値になり、okはtrueになります。
そうでない場合、okはfalseになり、tはT型のゼロ値になり、パニックは発生しません。
注:value i
はインターフェイスタイプである必要があります。
i
がインターフェース型であっても、[]i
はインターフェース型ではありません。その結果、[]i
をその値型に変換するには、個別に行う必要があります。
// var items []i
for _, item := range items {
value, ok := item.(T)
dosomethingWith(value)
}
パフォーマンスに関しては、 this stackoverflow answer に示すように、実際の値への直接アクセスよりも遅くなる可能性があります。
//an easy way:
str := fmt.Sprint(data)