Interface{}是任意值

类似C/C++的void* 类型指针或者Java语言的Object对象一样,使用场景一般做为函数的参数。

举个栗子:

func HelloWorld(value Interface){
     ....
}

函数的参数是一个Interface{}类型,在调用该函数的时候,可以传入多种类型的实参,其目的在于编写函数时,可以不关注具体传入实参变量的类型,从而达到代码复用的目的,这在golang标准库里面有很多的使用实例,比如fmt.prinltn()函数等等。


Interface 断言

上面提到Interface{}类型一般做为函数的形式参数,而针对形参可以划分两种,一种是在调用函数时,把参数值传入函数内部,实际copy一份值给函数内部,对副本的修改不影响外面原始值,即带入参数。另一种是,调用函数时传入的是实际参数的引用或者指针,函数内部的修改影响外面的值,即带出参数。往往在第二种情况想必大家在使用golang开发的时候也是经常遇到一个问题:把一个具体的类型转换成Interface{}类型后,怎么把Interface{}类型转换成具体的类型?

举个栗子:

...
import "encoding/json"
...	
if err := json.Unmarshal(incomingMsg, &in); err != nil {
		return nil, &invalidMessageError{err.Error()}
}
...

json包里面json.Unmarshal函数签名如下:

func Unmarshal(data []byte, v interface{}) error

可以看到第一个参数是带入参数,json格式的字节类型,第二个参数是带出参数,json格式的结构类型,想要获得带出参数的具体值,需要用到类型断言,也称类型查询,这是golang语言内置的语法。

if type, ok := var.(type), ok {
//正确的情况
}{
//错误的情况
}

或者

...
switch v := value.(type) {
     case string:
          fmt.Println("value时string)

     case int:
          fmt.Printfln("value时int类型)

}
...

需要注意的是,由于接口断言类型只能在运行期间才能确定下来,在编译期间随便给一个类型断言,只要不违法语法规则,编译器是不会给出任何错误提示的,所以必须保证具体类型能被查询到,保证捕获错误异常,否则,会造成程序panic,这也是golang做为强类型语言比较混乱,不严谨的地方。