10
package main

import (
    "fmt"
    "os/exec"
)

func main() {
    errChan := make(chan error)
    go func() {
        var e *exec.Error = nil
        errChan <- e
    }()
    err := <-errChan
    if err != nil {
        fmt.Printf("err != nil, but err = %v\n", err)
    }
}

出力は奇妙です:err != nil, but err = <nil> ここで試してみてください: http://play.golang.org/p/_iyh0m7O1a

4

2 に答える 2

15

問題は、エラー インターフェイスとしてチャネルに渡される値nilが ではなく、exec.Errornil を指すポインタであることです。

次のように変更すると、プログラムは正しく動作します。

go func() {
    var e *exec.Error = nil
    if e == nil {
        errChan <- nil
    }
}()

エラーが発生しなかったことを報告する慣用的な方法は、nil エラー インターフェイスを渡すことであるため、これが問題を解決する適切な方法です。

ただし、代わりにメインを変更する場合 (おそらく nil に設定されたポインターを返すという間違いを犯すサードパーティのパッケージを使用しているため)、特定の型 (*exec.Error) に対して型アサーションを実行する必要があります。 nil かどうかを確認するか、relect パッケージを使用します。

Reflect を使用して nil をチェックする例:

func IsNil(i interface{}) bool {
    // Check if it is an actual nil-value
    if i == nil {
        return true
    }

    v := reflect.ValueOf(i)
    switch v.Kind() {
        // Only the following kinds can be nil
        case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
        return v.IsNil()        
    }

    return false
}

作業例: http://play.golang.org/p/rpG1PVTwwM

ここでそれに関する議論を見つけることができます: https://groups.google.com/forum/#!topic/golang-nuts/QzVDKv7p0Vs

于 2013-10-11T11:36:02.020 に答える
2

注: この投稿は、潜在的に紛らわしい問題についてもう少し理解を深めるためのものです。 タイプのチャネルを使用する error ことは、エラーを送信する慣用的な方法です。

これを回避する別の方法は、チャネル署名を変更し、インターフェイス エラーのチャネルではなく、エラーへのチャネル ポインタであることを明示的に示すことです。

package main

import (
    "fmt"
    "os/exec"
)

func main() {
    errChan := make(chan *exec.Error)
    go func() {
        var e *exec.Error = nil
        errChan <- e
    }()
    err := <-errChan
    if err != nil {
        fmt.Printf("err != nil, but err = %v\n", err)
    } else {
    fmt.Printf("err == nil\n")
    }
}

http://play.golang.org/p/l6Fq8O0wJw

于 2013-10-11T19:15:41.883 に答える