212

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

最初、私は次のようなコードを持っていました:

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

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

4

4 に答える 4

330

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 */
}
于 2013-01-12T02:25:44.003 に答える
35

タイプアサーション

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

これがgoのツアーからの説明です:

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

t := i.(T)

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

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

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

t, ok := i.(T)

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

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

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

落とし穴

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

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

パフォーマンス

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

于 2016-12-03T10:58:00.173 に答える
25
//an easy way:
str := fmt.Sprint(data)
于 2016-06-24T08:28:15.527 に答える
6

@ρяσѕρєяによって求められたように、説明は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)
}
于 2020-05-21T08:52:47.643 に答える