怎样判断一个方法的interface{}参数是否为nil ?

102 views
Skip to first unread message

lulu Lee

unread,
Jul 11, 2012, 8:32:58 AM7/11/12
to golang-china
测试代码:

package main

import "fmt"

func main() {
type TT struct {}
var t *TT
test(t)
}

func test(i interface{}) {
fmt.Printf("%v => %v", i, i == nil)
}

返回结果为:<nil> => false

测试地址: http://play.golang.org/p/kDVSIna2Wd

--
@QLeelulu | FaWave, Net4 Team | qlee...@gmail.com | 学海无涯,回头是岸 

Jimmy Kuu

unread,
Jul 11, 2012, 10:46:56 AM7/11/12
to golang...@googlegroups.com
可以看看这篇文章,有说明,http://runtime.sinaapp.com/?p=24

2012/7/11 lulu Lee <qlee...@gmail.com>

steve wang

unread,
Jul 11, 2012, 11:04:49 AM7/11/12
to golang...@googlegroups.com
可以使用反射来处理。既然你用的是空接口,自然是要转成具体类型的。
个人感觉这个也算golang的复杂性(或者陷阱)之一吧。
func test(i interface{}) {
if i == nil {
fmt.Println("nil")
} else {
t := i.(*TT)
fmt.Println(t == nil)
}
}

> --
> 官网: http://golang-china.org/
> IRC: irc.freenode.net #golang-china
> @golangchina
>

lulu Lee

unread,
Jul 11, 2012, 1:12:11 PM7/11/12
to golang...@googlegroups.com
哎,现在就是用反射来解决了。
    v := reflect.ValueOf(i)
    if v.IsNil() {
        // xxxx
    }

蛋疼啊,性能啊。

另外如果接口可以支持类似C#的泛型就爽了。

Monnand

unread,
Jul 11, 2012, 1:33:52 PM7/11/12
to golang...@googlegroups.com


2012/7/11 lulu Lee <qlee...@gmail.com>

哎,现在就是用反射来解决了。
    v := reflect.ValueOf(i)
    if v.IsNil() {
        // xxxx
    }

蛋疼啊,性能啊。

其实大可不必为所谓性能操这么大心。在没有实际测试结果的支持下,很难说究竟是哪块才是性能瓶颈。你可以用prof看看,也许这块真就费不了。不是说用了reflect就肯定影响性能。

我前几天一个朋友的项目,也是出于性能的考虑,把核心的部分全部用汇编重写了一遍,充分利用了一些比较新的指令集。写好之后一测试,发现比原来c语言的版本慢了七倍。很多时候,我们自以为是优化了,其实还真不如编译器的优化呢。

xing

unread,
Jul 11, 2012, 8:37:11 PM7/11/12
to golang...@googlegroups.com
���ڸ����⣬��·��ţ�Ѿ�˵�ĺ�����ˣ����ڱ����ԭ���������golang faq���ҵ���
http://golang.org/doc/go_faq.html#nil_error

Under the covers, interfaces are implemented as two elements, a type and a value. The value, called the interface's dynamic value, is an arbitrary concrete value and the type is that of the value. For the int value 3, an interface value contains, schematically, (int, 3).

An interface value is nil only if the inner value and type are both unset, (nil, nil). In particular, a nil interface will always hold a nil type. If we store a pointer of type *int inside an interface value, the inner type will be *int regardless of the value of the pointer: (*int, nil). Such an interface value will therefore be non-nil even when the pointer inside is nil.

This situation can be confusing, and often arises when a nil value is stored inside an interface value such as an error return:

func returnsError() error {
	var p *MyError = nil
	if bad() {
		p = ErrBad
	}
	return p // Will always return a non-nil error.
}

If all goes well, the function returns a nil p, so the return value is an error interface value holding (*MyError, nil). This means that if the caller compares the returned error to nil, it will always look as if there was an error even if nothing bad happened. To return a proper nil error to the caller, the function must return an explicit nil:

func returnsError() error {
	if bad() {
		return ErrBad
	}
	return nil
}

It's a good idea for functions that return errors always to use the error type in their signature (as we did above) rather than a concrete type such as *MyError, to help guarantee the error is created correctly. As an example, os.Open returns an error even though, if not nil, it's always of concrete type *os.PathError.

Similar situations to those described here can arise whenever interfaces are used. Just keep in mind that if any concrete value has been stored in the interface, the interface will not be nil. For more information, see The Laws of Reflection.

����interface��ͬʱ����type��value��Ϣ�����뷴������ܲ�����Ҫ���ġ�ֻ������һ���������Եú������¡�
��Ȼ��ϲ��golang����golangҲ��һЩ�������ĵط���

�� 2012��07��12�� 01:33, Monnand �:


2012/7/11 lulu Lee <qlee...@gmail.com>
�������ھ����÷���������ˡ�
    v := reflect.ValueOf(i)
    if v.IsNil() {
        // xxxx
    }

���۰�����������

��ʵ��ɲ���Ϊ��ν���ܲ���ô���ġ���û��ʵ�ʲ��Խ���֧���£�����˵�������Ŀ��������ƿ�����������prof������Ҳ�� �����ͷѲ��ˡ�����˵����reflect�Ϳ϶�Ӱ�����ܡ�

��ǰ����һ�����ѵ���Ŀ��Ҳ�dz������ܵĿ��ǣ��Ѻ��ĵIJ���ȫ���û����д��һ�飬���������һЩ�Ƚ��µ�ָ���д��֮��һ ���ԣ����ֱ�ԭ��c���Եİ汾�����߱����ܶ�ʱ����������Ϊ���Ż��ˣ���ʵ���治����������Ż��ء�


�������ӿڿ���֧������C#�ķ��;�ˬ�ˡ�

�� 2012��7��11�� ����11:04��steve wang <steve....@gmail.com>д ����

����ʹ�÷��������?��Ȼ���õ��ǿսӿڣ���Ȼ��Ҫת�ɾ������͵ġ�
���˸о����Ҳ��golang�ĸ����ԣ��������壩֮һ�ɡ�

func test(i interface{})  {
        if i == nil {
                fmt.Println("nil")
        } else {
                t := i.(*TT)
                fmt.Println(t == nil)
        }
}

On 7/11/12, Jimmy Kuu <jimm...@gmail.com> wrote:
> ���Կ�����ƪ���£���˵����http://runtime.sinaapp.com/?p=24
>
> 2012/7/11 lulu Lee <qlee...@gmail.com>
>
>> ���Դ��룺

>>
>> package main
>>
>> import "fmt"
>>
>> func main() {
>> type TT struct {}
>>  var t *TT
>> test(t)
>> }
>>
>> func test(i interface{}) {
>> fmt.Printf("%v => %v", i, i == nil)
>> }
>>
>> ���ؽ��Ϊ��<nil> => false
>>
>> ���Ե�ַ�� http://play.golang.org/p/kDVSIna2Wd
>
> --
> ����: http://golang-china.org/

> IRC:  irc.freenode.net     #golang-china
> @golangchina
>

--
����: http://golang-china.org/
IRC:  irc.freenode.net     #golang-china
@golangchina



--
@QLeelulu | FaWave, Net4 Team | qlee...@gmail.com | ѧ ������,��ͷ�ǰ� 
--
����: http://golang-china.org/
IRC: irc.freenode.net #golang-china
@golangchina

--
����: http://golang-china.org/
IRC: irc.freenode.net #golang-china
@golangchina


Xing Xing

unread,
Jul 11, 2012, 9:45:04 PM7/11/12
to golang...@googlegroups.com
于 Wed, 11 Jul 2012 23:04:49 +0800
steve wang <steve....@gmail.com> 写道:

> 可以使用反射来处理。既然你用的是空接口,自然是要转成具体类型的。
> 个人感觉这个也算golang的复杂性(或者陷阱)之一吧。
> func test(i interface{}) {
> if i == nil {
> fmt.Println("nil")
> } else {
> t := i.(*TT)
> fmt.Println(t == nil)
> }
> }
>

我也觉得,在具体环境的代码中,类型断言可能会比反射来得实用。
string、int 之类的类型的零值不是
nil。如果用反射判断,那可能还要判断一下 Kind 什么的,很繁琐的感觉。

shiwei xu

unread,
Jul 11, 2012, 9:53:26 PM7/11/12
to golang...@googlegroups.com
我个人感觉是你对 go 编程范式不太了解的原因引起的。我们写了十几万行的 go 代码,也没有为这个问题纠结过。

我们通常的方式是,如果一个函数可能出错,那么应该返回 error。比如:

func NewTT() (tt *TT, err error) {
    ...
}

用的时候:

tt, err := NewTT()
if err != nil {
   return
}

... // tt 确认不是 nil

xing

unread,
Jul 11, 2012, 10:04:49 PM7/11/12
to golang...@googlegroups.com
�������ȷʵ����Ҫ����, ���NewTT���������ŵù���˱�д�Ļ���Ҫ�Dz��˽�go����д�����µĴ��룬�ͻᵼ���ϲ�������жϳ��?
func NewTT() (tt *TT, err error) {
	var p *MyError = nil
	if bad() {
		p = ErrBad
		return new(TT), p
	 }
	return nil, p // Will always return a non-nil error.
}


�� 2012��07��12�� 09:53, shiwei xu �:
�Ҹ��˸о������ go ��̷�ʽ��̫�˽��ԭ������ġ�����д��ʮ�����е� go ���룬Ҳû��Ϊ�����������

����ͨ���ķ�ʽ�ǣ����һ��������ܳ��?��ôӦ�÷��� error�����磺

func NewTT() (tt *TT, err error) {
    ...
}

�õ�ʱ��

tt, err := NewTT()
if err != nil {
   return
}

... // tt ȷ�ϲ��� nil


�� 2012��7��12�� ����1:12��lulu Lee <qlee...@gmail.com>д ����
�������ھ����÷����� ����ˡ�
    v := reflect.ValueOf(i)
    if v.IsNil() {
        // xxxx
    }

���۰�����������

�������ӿڿ���֧������C#�ķ��;�ˬ�ˡ�

�� 2012��7��11�� ����11:04��steve wang <steve....@gmail.com>д ����
����ʹ�÷��������?��Ȼ���õ��ǿսӿڣ���Ȼ��Ҫת�ɾ������͵ġ�
���˸о����Ҳ��golang�ĸ����ԣ��������壩֮һ�ɡ�
func test(i interface{})  {
        if i == nil {
                fmt.Println("nil")
        } else {
                t := i.(*TT)
                fmt.Println(t == nil)
        }
}

On 7/11/12, Jimmy Kuu <jimm...@gmail.com> wrote:
> ���Կ�����ƪ���£���˵����http://runtime.sinaapp.com/?p=24
>
> 2012/7/11 lulu Lee <qlee...@gmail.com>
>
>> ���Դ��룺

>>
>> package main
>>
>> import "fmt"
>>
>> func main() {
>> type TT struct {}
>>  var t *TT
>> test(t)
>> }
>>
>> func test(i interface{}) {
>> fmt.Printf("%v => %v", i, i == nil)
>> }
>>
>> ���ؽ��Ϊ��<nil> => false
>>
>> ���Ե�ַ�� http://play.golang.org/p/kDVSIna2Wd
>
> --
> ����: http://golang-china.org/

> IRC:  irc.freenode.net     #golang-china
> @golangchina
>

--
����: http://golang-china.org/
IRC:  irc.freenode.net     #golang-china
@golangchina



--
@QLeelulu | FaWave, Net4 Team | qlee...@gmail.com | ѧ ������,��ͷ�ǰ� 
--
����: http://golang-china.org/
IRC: irc.freenode.net #golang-china
@golangchina



--
��ʽΰ
--
����: http://golang-china.org/
IRC: irc.freenode.net #golang-china
@golangchina


lulu Lee

unread,
Jul 12, 2012, 1:00:58 AM7/12/12
to golang...@googlegroups.com
再问一个问题,如果判断为nil怎样新建一个实例并赋值给原来的指针呢?

package main

import "fmt"
import "reflect"

func main() {
type TT struct { a int }
var t *TT
test(t)
fmt.Printf("Result t: %s", t)
}

// i是指针
func test(i interface{}) {
v := reflect.ValueOf(i)
if v.IsNil() {
// 这里怎样新建一个i的实例
// 下面的代码是不正确的
structType := reflect.TypeOf(i).Elem()
v = reflect.New(structType)
fmt.Printf("new: %s\n", v.Interface())
i = v.Interface()
}
}


在 2012年7月12日 上午10:04,xing <xing.zhang....@gmail.com>写道:
这个问题确实不需要纠结, 如果NewTT方法是由信得过的人编写的话。要是不了解go的人写出如下的代码,就会导致上层调用者判断出错:

func NewTT() (tt *TT, err error) {
	var p *MyError = nil
	if bad() {
		p = ErrBad
		return new(TT), p
	 }
	return nil, p // Will always return a non-nil error.
}


于 2012年07月12日 09:53, shiwei xu 写道:
我个人感觉是你对 go 编程范式不太了解的原因引起的。我们写了十几万行的 go 代码,也没有为这个问题纠结过。

我们通常的方式是,如果一个函数可能出错,那么应该返回 error。比如:

func NewTT() (tt *TT, err error) {
    ...
}

用的时候:

tt, err := NewTT()
if err != nil {
   return
}

... // tt 确认不是 nil


在 2012年7月12日 上午1:12,lulu Lee <qlee...@gmail.com>写 道:
哎,现在就是用反射来 解决了。
    v := reflect.ValueOf(i)
    if v.IsNil() {
        // xxxx
    }

蛋疼啊,性能啊。

另外如果接口可以支持类似C#的泛型就爽了。

在 2012年7月11日 下午11:04,steve wang <steve....@gmail.com>写 道:
可以使用反射来处理。既然你用的是空接口,自然是要转成具体类型的。
个人感觉这个也算golang的复杂性(或者陷阱)之一吧。
func test(i interface{})  {
        if i == nil {
                fmt.Println("nil")
        } else {
                t := i.(*TT)
                fmt.Println(t == nil)
        }
}

On 7/11/12, Jimmy Kuu <jimm...@gmail.com> wrote:
> 可以看看这篇文章,有说明,http://runtime.sinaapp.com/?p=24
>
> 2012/7/11 lulu Lee <qlee...@gmail.com>
>
>> 测试代码:

>>
>> package main
>>
>> import "fmt"
>>
>> func main() {
>> type TT struct {}
>>  var t *TT
>> test(t)
>> }
>>
>> func test(i interface{}) {
>> fmt.Printf("%v => %v", i, i == nil)
>> }
>>
>> 返回结果为:<nil> => false
>>
>> 测试地址: http://play.golang.org/p/kDVSIna2Wd
>
> --

> IRC:  irc.freenode.net     #golang-china
> @golangchina
>

--
官网: http://golang-china.org/
IRC:  irc.freenode.net     #golang-china
@golangchina



--
@QLeelulu | FaWave, Net4 Team | qlee...@gmail.com | 学 海无涯,回头是岸 
--
官网: http://golang-china.org/
IRC: irc.freenode.net #golang-china
@golangchina



--
许式伟
--
官网: http://golang-china.org/
IRC: irc.freenode.net #golang-china
@golangchina


--
官网: http://golang-china.org/
IRC: irc.freenode.net #golang-china
@golangchina



--
@QLeelulu | FaWave, Net4 Team | qlee...@gmail.com | 学海无涯,回头是岸 

minux

unread,
Jul 12, 2012, 2:52:34 AM7/12/12
to golang...@googlegroups.com

On Wednesday, July 11, 2012, lulu Lee wrote:
再问一个问题,如果判断为nil怎样新建一个实例并赋值给原来的指针呢?
package main

import "fmt"
import "reflect"

func main() {
type TT struct { a int }
var t *TT
test(t)
fmt.Printf("Result t: %s", t)
}
光看这段代码就知道问题所在了:一没把t本身的地址传给test函数,
二来t还是个空指针,你如何能让test函数改变t?
 

wxf

unread,
Jul 12, 2012, 9:27:13 AM7/12/12
to golang...@googlegroups.com
这个应该是你对interface的理解有误,虽然打印的是nil,但是i的值并不是nil,是t *TT,t的值是nil,如果你调用test(nil)的话,结果是:<nil> => true。


2012/7/11 lulu Lee <qlee...@gmail.com>
--
Reply all
Reply to author
Forward
0 new messages