目前我正在使用此辅助函数来检查nil和nil接口
func isNil(a interface{}) bool {
defer func() { recover() }()
return a == nil || reflect.ValueOf(a).IsNil()
}
如果reflect.ValueOf(a).IsNil()
值不是Chan
,Func
,Map
,Ptr
,Interface
或{{},那么Slice
会发生恐慌1}},我把延迟的recover()
扔进去抓住那些。
有更好的方法来实现这项检查吗?它认为应该有一个更直接的方法来做到这一点。
答案 0 :(得分:28)
在golang-nuts邮件列表中查看Kyle在此thread中的答案。
简而言之:如果您从未在界面中存储(*T)(nil)
,那么您可以可靠地使用与nil的比较,无需使用反射。另一方面,将无类型的nil分配给接口总是正常的。
答案 1 :(得分:9)
如果以前的选项都不适合你,那么到目前为止我能做到的最好的选择是:
if c == nil || (reflect.ValueOf(c).Kind() == reflect.Ptr && reflect.ValueOf(c).IsNil())
至少检测到(* T)(无)个案。
答案 2 :(得分:3)
两种解决方案不使用反射:
将代码复制并粘贴到编辑器:https://play.golang.org/以查看实际情况。
以下代码:
<强>一一一一一一一一一一一一一一一一一一一一强>
示例#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;
}
<强>一一一一一一一一一一一一一一一一一一一一强>
示例#2:键入Switch
<强>一一一一一一一一一一一一一一一一一一一一强>
//: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()()
}
<强>更新强> 在我的代码库中实现后,我发现#2(类型切换)是最佳解决方案。特别是因为我不想在我正在使用的绑定库中编辑glfw.Window结构。这是我用例的粘贴框。 为我的非标准编码风格道歉。 https://pastebin.com/22SUDeGG
答案 3 :(得分:0)
这是此示例解决方案的接口定义:
package checker
import (
"errors"
"github.com/rs/zerolog"
)
var (
// ErrNilChecker returned if Check invoked on a nil checker
ErrNilChecker = errors.New("attempted Check with nil Checker")
// ErrNilLogger returned if the Check function is provide a nil logger
ErrNilLogger = errors.New("nil logger provided for Check")
)
// Checker defines the interface
type Checker interface {
Check(logger *zerolog.Logger) error
}
我们的Checker实现之一支持Checkers的聚合。但是测试发现了与此线程相同的问题。
如果简单的nil检查失败,则此解决方案将使用reflect
软件包,并利用reflect.Value
类型来解决问题。
// AggregateChecker implements the Checker interface, and
// supports reporting the results of applying each checker
type AggregateChecker struct {
checkers []Checker
}
func (ac *AggregateChecker) Add(aChecker Checker) error {
if aChecker == nil {
return ErrNilChecker
}
// It is possible the interface is a typed nil value
// E.g. checker := (&MyChecker)(nil)
t := reflect.TypeOf(aChecker)
if reflect.ValueOf(aChecker) == reflect.Zero(t) {
return ErrNilChecker
}
ac.checkers = append(ac.checkers, aChecker)
return nil
}
答案 4 :(得分:0)
考虑inboundData
作为您的界面
使用len()
函数检查接口中是否有数据
if inboundData != nil && len(inboundData) > 0 {
// ... do stuff | data is present
} else {
// ... data is not present
}
答案 5 :(得分:0)
func main() {
var foo interface{}
fmt.Println(reflect.TypeOf(foo) == nil) // true
type Bar struct{}
var bar *Bar
fmt.Println(reflect.TypeOf(bar) != nil) // true
}
答案 6 :(得分:0)
也许您尝试在填充界面的函数中使用错误:
打包一个
func getObj() (obj *someObject, err error) {
obj = db.getA()
if obj == nil {
err = fmt.Errorf("Some error")
}
return
}
包 b
import a
var i interface{}
i, err = a.getObj()
if err != nil {
// catch err
} else {
// do next step
}