golang接口的一些见解

问题

今天在做LeetCode时,需要一个函数delChar,用于把一个字符串中的指定字符删除掉:

1
2
3
4
5
6
7
8
9
func DelChar(s string, char byte) string {
res := make([]byte, 0)
for i := 0; i < len(s); i++ {
if s[i] != char {
res = append(res, s[i])
}
}
return string(res)
}

然后我突发奇想:如果有一个函数,接收任意的数组类型,删除其等于指定值的所有元素,那岂不很方便.说干就干!

1
2
3
4
5
6
7
8
9
func DeleteElement(array []interface{}, element interface{}) []interface{} {
res := make([]interface{}, 0)
for i := 0; i < len(array); i++ {
if array[i] != element {
res = append(res, array[i])
}
}
return res
}

嗯,看上去很完美,然后运行:

1
DeleteElement("1234512345",'1')

输出:

./hello.go:5:23: cannot use s (type string) as type []interface {} in argument to DeleteElement

嗯…string类型不能转换为[]interface{}类型,那换字节切片看看:

1
DeleteElement([]byte("1234512345"),'1')

输出:

./hello.go:4:30: cannot use ([]byte)("1234512345") (type []byte) as type []interface {} in argument to DeleteElement

也不行,这是为什么呢?如果这两种类型都不能转换为[]interface{}类型,那还有什么类型能转换的么,直接用[]interface{}类型试试?

1
2
3
4
5
inter:=make([]interface{},3)
inter[0]=0
inter[1]="hello"
inter[2]=1.1
fmt.Println(DeleteElement(inter,0))

输出:

[hello 1.1]

终于成功了…不过这么看来,[]interface{}只能接受和它相同的类型才行,这有什么用?在网上查了资料,解释如下:

  • []interface{}类型并非interface{}类型,它实际上是一个每个元素都是interface{}类型的切片.因此不能将其他类型如string,[]byte复制给[]interface{}
  • 每个interface{}类型都占用2个字(WORD),一个字存储其底层变量的类型,另一个字存储其底层变量的值.一个长度为n的[]interface{}变量的大小为2*n个字;而[]MyType的大小则为sizeof(MyType)*n.两者长度不相同,因此不能转换

在我看来,[]byte(示例)类型不能转换为[]interface{}类型的原因还有一点:[]byte类型可以表示为interface{}类型,如果它还能转换为[]interface{}类型的话,那么编译器就不知道它到底该转换成什么类型了

值得一提的是,像其它所有类型一样,[]interface{}也可以转换为interface{}类型

解决方案

那么,如果真的想要写这样一个函数,该怎么写呢?

一个想法是使用可变参数函数,尽可能避免使用[]interface{}类型

1
2
3
4
5
6
7
8
9
func DeleteElement(element interface{}, array ...interface{}) []interface{} {
res := make([]interface{}, 0)
for i := 0; i < len(array); i++ {
if array[i] != element {
res = append(res, array[i])
}
}
return res
}

然而返回值貌似还得是[]interface{}…这种返回值看来只能一个个将里面的元素转换为其他类型了

小结

记得之前看过一篇文章说过,interface{}类型像是golang中的潘多拉魔盒,给开发者带来强大力量的同时也留下无穷后患.对于golang这种强类型语言来说,interface{}这种近乎动态的万能类型还是用得越少越好

参考文档

segmentfault:golang []interface{} 的数组如何转换为 []string 的数组

github:golang的wiki:InterfaceSlice

0%