Golang入门——空接口

Golang入门——空接口

  • 什么是空接口以及空接口的简单使用方法
  • 使用空接口构建通用类型或者包含不同类型变量的数组
  • 复制数据切片至空接口切片
  • 使用空接口实现通用类型的节电数据结构
  • 代码下载

什么是空接口以及空接口的简单使用方法

空接口或者最小接口不包含任何方法,对实现不做任何要求。
形如:

type Any interface{}

空接口类似于Java/C#中的所有类的基类:Object 类。
可以给空接口变量赋予任何类型的值

type rectangle struct {  
  	height float64  
 	width float64  
}  
  
type Any interface{}  
  
func main() {  
  	var any Any  
 	any = 5  
 	fmt.Printf("%v,%[1]T\n", any)//5,int
 	any = "Hello,World"  
 	fmt.Printf("%v,%[1]T\n", any)//Hello,World,string
  	any = &rectangle{height: 4, width: 5}  
  	fmt.Printf("%v,%[1]T\n", any) //&{4 5},*main.rectangle
}

每个 interface{ } 变量在内存中占据两个字节:

  1. 一个用来存储它包含的类型
  2. 另一个用来存储它包含的数据或者指向的指针

空接口也可以配合lambda函数 (匿名函数) 进行使用:

func TypeSwitch(){  
  testFunc := func(any interface{}) {  
    switch any.(type){  
    case bool:  
      fmt.Println("The type of any is Bool")  
    case int:  
      fmt.Println("The type of any is Int")  
    case float32:  
      fmt.Println("The type of any is Float32")  
    case string:  
      fmt.Println("The type of any is string")  
    default:  
      fmt.Println("The type of any is Unknow")  
    }  
  }  
  testFunc("Hello,World")  // The type of any is string
}

以上函数是空接口在type-switch中联合使用了lamdba函数

使用空接口构建通用类型或者包含不同类型变量的数组

除了我们常用的能被搜索和排序的int数组float数组string数组,对于其他类型的数组我们可以通过使用空接口来实现。这里先举一个简单的例子:

type rectangle struct {  
	height float64  
	width float64  
}  
type Any interface{}  
func main() {  
 	var a = new([3]Any)  
 	a[0] = "Hello,World"  
	a[1] = 32  
	a[2] = &rectangle{3,4}  
 	for _,b := range a {  
   		fmt.Printf("%v\t%[1]T\n",b)  
  }  
}

其中 变量a 存储三个空接口(Any),在对每个空接口进行赋值,并进行输出,即可实现同一个数组包含不同数据类型。其输出结果如下:

Hello,World	string
32	int
&{3 4}	*main.rectangle

此外我们可以定义一个容器类型的结构体来包含空接口(Any)类型的元素切片。

type Container struct{
	a []Any
}

其中Container里面可以存放任何类型的变量,因为空接口可以赋予任何类型的值。
我们可以定义一个方法 At 用于返回第 i 个元素的值,同时我们也可以定义一个方法 Set 用于设置第 i 个元素的值。如下:

func (p *Container) Set(i int, e Any){  
  p.a[i] = e  
}  
func (p *Container) At(i int) Any{  
  return p.a[i]  
}

因此我们可以切片来对原数组进行修改。对之间的简例进行修改得到的完整的函数如下:

type rectangle struct {  
	 height float64  
	 width float64  
}  
type Any interface{}  
type Container struct{  
	  a []Any  
}  
func (p *Container) Set(i int, e Any){  
	p.a[i] = e  
}  
func (p *Container) At(i int) Any{  
	return p.a[i]  
}
func main() {  
	 var a = new([3]Any)  
	 b := Container{a[:]}  
	 a[0] = "Hello,World"  
	 a[1] = 32  
	 a[2] = &rectangle{3,4}  
	 b.Set(0,"Hello")  
	 b.Set(1,123.4)  
	 for c := range a {  
		fmt.Printf("%v\t%[1]T\n",b.At(c))  
  }  
}  

其输出结果如下:

Hello	string
123.4	float64
&{3 4}	*main.rectangle

通过结果的对比可得已实现At、Set方法,即不仅可以修改数据的值,同时也可以修改数据的类型。

复制数据切片至空接口切片

由于空接口切片的布局于一般数据切片不同,故无法使用 ‘ = ‘ 直接进行复制。编译时会出现错误。

cannot use dateSlice (type [ ] myType) as type [ ] interface { } in assignment

所以在进行复制时必须使用 for-range 一个一个地进行显式赋值,具体代码如下

dateSlice := &[...]int{1,2,3}  
var interfaceSlice []Any = make([]Any,len(dateSlice))  
for i,d := range dateSlice{  
	interfaceSlice[i] = d  
}  
fmt.Println(*dateSlice)  
fmt.Println(interfaceSlice)

输出结果如下:

[1 2 3]
[1 2 3]

发现interfaceSlice已经复制了dateSlice的内容

使用空接口实现通用类型的节电数据结构

该例子由空接口存储数据的一个二叉树:

type Node struct {  
	left *Node  
	data interface{}  
	right *Node  
}  
func NewNode(left,right *Node) *Node{  
	return &Node{left,nil,right}  
}  
func (n *Node) SetData(data interface{}){  
	n.data = data  
}
func main(){
	root := NewNode(nil,nil)  
	root.SetData("Root Node")  
	leftChild := NewNode(nil,nil)  
	leftChild.SetData("Left Node")  
	rightChile := NewNode(nil,nil)  
	rightChile.SetData("Right Node")  
	root.left = leftChild  
	root.right = rightChile  
	fmt.Printf("%v",root)
}

输出结果为:

&{0xc000022060 Root Node 0xc000022080}

其中0xc000022060和0xc000022080为左右孩子结点的地址。

代码下载

以上程序代码均已上传到至Github ,有需要可直接进行下载

你可能感兴趣的:(Golang基础入门,golang)