1.空接口,interface{}
空接口类型interface{}一个方法签名也不包含,所以所有的数据类型都实现了该方法。
空接口类型在描述一个对象实例的行为上力不从心,但是当我们需要存储任意数据类型的实例的时候,空接口类型的使用使得我们得心应手。
如果一个函数的参数包括空接口类型interface{},实际上函数是在说“兄弟,我接受任何数据”。如果一个函数返回一个空接口类型,那么函数再说“我也不确定返回什么,你只要知道我一定返回一个值就好了”。
package main import ( "fmt" ) func main(){ var a interface{} var b int = 1000 a = b fmt.Println(a) //1000 var c string = "hello" a = c fmt.Println(a) //hello }
2.接口嵌套
package main import ( "fmt" ) type Eater interface { Eat() } type Talker interface { Talk() } type Animal interface { //接口嵌套 字段直接写上其它接口的名字,也可以定义其它的方法集合 Eater Talker } type Dog struct { } func (d *Dog) Eat() { fmt.Println("eating") } func (d *Dog) Talk() { fmt.Println("eating") } type Cat struct { } func (c *Cat) Eat() { fmt.Println("eating") } func (c *Cat) Talk() { fmt.Println("eating") } func main() { d := &Dog{} var a Animal a = d a.Eat() //eating }
3.类型断言
就是说如何知道接口里存储的对象的类型
func testassertion() { var a int var i interface{} a = 100 i = a y := i.(int) //类型转换 fmt.Println(y) //100 } func testassertion() { var a int var i interface{} a = 100 i = a // y := i.(int) y := i.(string) //类型转换,转换成 string fmt.Println(y) //panic: interface conversion: interface {} is int, not string } 上面的例子没有判断,一旦类型转换失败程序运行会中断,下面会加上判断 func testassertion() { var a int var i interface{} a = 100 i = a // y := i.(int) y, ok := i.(string) if !ok { //判断 fmt.Println("this is not string") return } fmt.Println(y) }
4.上面的判断局限性比较大,下面我们用swtich来判断,这样可以覆盖基本的数据类型
package main import ( "fmt" ) func justify(items ...interface{}) { for index, v := range items { switch v.(type) { //判断传入参数的类型 case int: fmt.Printf("第 %d 个参数 is int ", index) case int32: fmt.Printf("第 %d 个参数 is int32 ", index) case float32: fmt.Printf("第 %d 个参数 is float32 ", index) } } } func main(){ var a int var b float32 var c int32 justify(a, b, c) } //运行结果 第 0 个参数 is int 第 1 个参数 is float32 第 2 个参数 is int32
5.判断变量是否实现了接口
import ( "fmt" ) type SSSS interface { //定义接口 sing(s string) } type Man struct { Name string } func (m *Man) sing(name string) { //实现接口 fmt.Printf("%s is la la la la %s", m.Name, name) } func main() { var s SSSS m := &Man{ Name: "xiao ming", } s = m fmt.Println(s) fmt.Println(m.Name) var n interface{} n = m //把m存入n这个空接口 if sv, ok := n.(SSSS); ok { //判断n是否实现SSSS这个接口 sv.sing("爱在回首间") } } //运行结果: &{xiao ming} xiao ming xiao ming is la la la la 爱在回首间
6.以上的例子给我们展示了一个接口类型如何存储满足他的的数据类型实例,并且展示给我们如何创建存储不同数据类型实例的集合。
利用此思想,我们还可以让函数来接受满足特定接口类型的数据类型实例。
举例来说,我们已经知道fmt.Print 是一个可变参数的函数,他可以接受任意数量的参数。但是你有没有注意到,有时候我们使用的是strings、ints和floats?
事实上,如果你深入去看fmt包,你就会看到如下的接口声明:
//The Stringer interface found in fmt package
type Stringer interface {
String() string
}
任何数据类型,只要实现了Stringer接口,就能够传递给fmt.Print函数,然后打印出该类型String()函数的返回值。
package main import ( "fmt" "strconv" //for conversions to and from string ) type Human struct { //定义结构体 name string age int phone string } //Returns a nice string representing a Human //With this method, Human implements fmt.Stringer func (h Human) String() string { //实现 String()方法 //We called strconv.Itoa on h.age to make a string out of it. //Also, thank you, UNICODE! return "❰"+h.name+" - "+strconv.Itoa(h.age)+" years - ✆ " +h.phone+"❱" } func main() { Bob := Human{"Bob", 39, "000-7777-XXX"} fmt.Println("This Human is : ", Bob) //fmt.Println函数接收实现了String接口的参数 } //输出结果: This Human is : ❰Bob - 39 years - ✆ 000-7777-XXX❱
参考:https://www.jianshu.com/p/dbd4e6b4900c