データ(タイプインターフェース{})をタイプ文字列に変換できません:タイプアサーションが必要です


176

私は行くのはかなり新しいです、そして私はこの通知パッケージで遊んでいました。

最初は次のようなコードがありました。

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)
}

これは私がすることになっていたことですか?コンパイラのエラーがなくなったので、それでかなり良いと思いますか?これは効率的ですか?別の方法で行う必要がありますか?

回答:


291

Go仕様によると:

インターフェイスタイプとタイプTの式xの場合、1次式x。(T)は、xがnilではなく、xに格納されている値がタイプTであることを表明します。

「型アサーション」を使用すると、特定の具象型を含むインターフェース値、またはその具象型が別のインターフェースを満たすことを宣言できます。

あなたの例では、データ(型インターフェイス{})が具象型文字列を持っていると主張していました。間違っていると、プログラムは実行時にパニックになります。効率を気にする必要はありません。チェックには2つのポインタ値を比較するだけです。

文字列かどうかわからない場合は、2つのreturn構文を使用してテストできます。

str, ok := data.(string)

データが文字列でない場合、okはfalseになります。その場合、そのようなステートメントを次のようなifステートメントにラップするのが一般的です。

if str, ok := data.(string); ok {
    /* act on str */
} else {
    /* not string */
}

29

タイプアサーション

これはtype assertiongolangで知られていますが、一般的な方法です。

goのツアーの説明は次のとおりです。

タイプアサーションは、インターフェース値の基礎となる具体的な値へのアクセスを提供します。

t := i.(T)

このステートメントは、インターフェイス値 iが具象型 Tを保持し、基になるT値を変数tに割り当てることを表明します

Tを保持していない場合、ステートメントはパニックを引き起こします。

インターフェイス値が特定の型を保持しているかどうかをテストするために、型アサーションは2つの値を返すことができます。基礎となる値と、アサーションが成功したかどうかを報告するブール値です。

t, ok := i.(T)

iがTを保持している場合、tは基礎となる値になり、okはtrueになります。

そうでない場合、okはfalseになり、tはタイプTのゼロ値になり、パニックは発生しません。

注:iはインターフェースタイプである必要があります

落とし穴

iがインターフェイスタイプであっても、はインターフェイスタイプで[]iはありません。その結果、[]iその値型に変換するには、個別に行う必要があります。

// var items []i
for _, item := range items {
    value, ok := item.(T)
    dosomethingWith(value)
}

パフォーマンス

パフォーマンスに関しては、このスタックオーバーフローの回答に示されているように、実際の値に直接アクセスするよりも遅くなる可能性があります。


13
//an easy way:
str := fmt.Sprint(data)

21
現在の問題を修正する方法で、この答えのヘルプOPのための答えを持ついくつかの説明を追加
ρяσѕρєяK

2

@ρяσѕρєяが求めたように、説明はhttps://golang.org/pkg/fmt/#Sprintにあります。関連する説明は、https://stackoverflow.com/a/44027953/12817546およびhttps://stackoverflow.com/a/42302709/12817546にあります。@Yuanboの答えはここにあります。

package main

import "fmt"

func main() {
    var data interface{} = 2
    str := fmt.Sprint(data)
    fmt.Println(str)
}

1
あなたは両方の入金されますと、あなたのそれぞれの「有用性」スコア😉まで追加-私はあなたが単にYuanboの@編集することによって、両方の答えを組み合わせることができると思います
グウィネスLlewelynを
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.