Vraag Controleer op nul en nul interface in Go


Momenteel gebruik ik deze hulpfunctie om te controleren op nul- en nul-interfaces

func isNil(a interface{}) bool {
  defer func() { recover() }()
  return a == nil || reflect.ValueOf(a).IsNil()
}

Sinds reflect.ValueOf(a).IsNil() paniek als de waarde Soort anders is dan Chan, Func, Map, Ptr, Interface of Slice, Ik gooide in de uitgestelde recover() om die te vangen.

Is er een betere manier om deze controle te bereiken? Het vindt dat er een meer rechtlijnige manier moet zijn om dit te doen.


29
2017-11-20 15:21


oorsprong


antwoorden:


Zie bijvoorbeeld het antwoord van Kyle hierin draad op de Golang-noten mailinglijst.

Kortom: als u nooit opslaat (*T)(nil) in een interface, dan kun je op betrouwbare wijze vergelijking met nul gebruiken, geen noodzaak om reflectie te gebruiken. Aan de andere kant is het toewijzen van niet-geheelde nihil aan een interface altijd OK.


22
2017-11-20 15:43



Twee oplossingen NIET gebruik van reflectie:

Kopieer en plak de code in de editor bij: https://play.golang.org/ om te zien in actie.

1: voeg een "IsInterfaceNil ()" -functie toe om te communiceren.

2: Gebruik A "type switch"

CODE HIERONDER:

一一 一一 一一 一一 一一 一一 一一 一一 一一 一一

VOORBEELD # 1: IsInterfaceNil ()

一一 一一 一一 一一 一一 一一 一一 一一 一一 一一

//:Example #1:
//:I prefer this method because the 
//:TakesInterface function does NOT need to know
//:about all the different implementations of
//:the interface.
package main;
import "fmt";

func main()(){

    var OBJ_OK *MyStruct = &( MyStruct{} );
    var NOT_OK *MyStruct = nil;

    //:Will succeed:
    TakesInterface( OBJ_OK );

    //:Will fail:
    TakesInterface( NOT_OK );

}

func TakesInterface( input_arg MyInterface ){

    if( input_arg.IsInterfaceNil() ){
        panic("[InputtedInterfaceIsNil]");
    }

    input_arg.DoThing();
}

type MyInterface interface{
    DoThing()()
    IsInterfaceNil()(bool)
}
type MyStruct struct{}
func(f *MyStruct)DoThing()(){
    fmt.Println("[MyStruct.DoThing]");
}
func(f *MyStruct)IsInterfaceNil()(bool){
    if(nil==f){ return true; }
    return false;
}

一一 一一 一一 一一 一一 一一 一一 一一 一一 一一

VOORBEELD # 2: Type schakelaar

一一 一一 一一 一一 一一 一一 一一 一一 一一 一一

//:Example #2:
//:This will also work, but the function taking
//:the interface needs to know about all 
//:implementations. This defeats a bit of the
//:decoupling from implementation that an
//:interface offers, but if you are just using
//:interfaces for polymorphism, it's probably
//:an okay way to go. (opinion)
package main;
import "fmt";

func main()(){

    //:Will succeed:
    var OBJ_OK *IMPLMENTS_INTERFACE_01 = 
             &( IMPLMENTS_INTERFACE_01{} );
    TakesInterface( OBJ_OK );

    //:Will fail:
    var NOT_OK *IMPLMENTS_INTERFACE_01 = nil;
    TakesInterface( NOT_OK );
}

func TakesInterface( hasDoThing MyInterface ){

    //:THIS WILL NOT WORK:
    if(nil==hasDoThing){
        panic("[This_Error_Message_Will_Never_Happen]");
    }

    //:TYPE SWITCH TO THE RESCUE:
    switch v := hasDoThing.(type){

        case (*IMPLMENTS_INTERFACE_01): 
        if(nil==v){ panic("[Nil_PTR_01]"); }

        case (*IMPLMENTS_INTERFACE_02): 
        if(nil==v){ panic("[Nil_PTR_02]"); }

        case (*IMPLMENTS_INTERFACE_03): 
        if(nil==v){ panic("[Nil_PTR_03]"); }

        default: 
            panic("[UnsupportedInterface]");
    }

    hasDoThing.DoThing();

}

type IMPLMENTS_INTERFACE_01 struct{};
type IMPLMENTS_INTERFACE_02 struct{};
type IMPLMENTS_INTERFACE_03 struct{};
func (f *IMPLMENTS_INTERFACE_01)DoThing()(){
    fmt.Println( "DoingTheThing_01" );
}
func (f *IMPLMENTS_INTERFACE_02)DoThing()(){
    fmt.Println( "DoingTheThing_02" );
}
func (f *IMPLMENTS_INTERFACE_03)DoThing()(){
    fmt.Println( "DoingTheThing_03" );
}

type MyInterface interface{
    DoThing()()
}

BIJWERKEN: Na implementatie in mijn codebasis, vond ik # 2 (typeschakelaar) de beste oplossing. In het bijzonder omdat ik de glfw.Window struct NIET wil BEWERKEN in de bindingsbibliotheek die ik gebruik. Hier is een prullenbak van mijn use-case. Excuses voor mijn niet-standaard codeerstijl. https://pastebin.com/22SUDeGG


2
2018-02-28 00:45



Als geen van de eerdere opties voor u werkt, is het beste wat ik tot nu toe heb gedaan:

if c == nil || (reflect.ValueOf(c).Kind() == reflect.Ptr && reflect.ValueOf(c).IsNil())

Het detecteert tenminste (* T) (nul) gevallen.


1
2018-05-23 11:21