最近工作中在做一些功能测试和代码重构,出现了一个挺有意思的小问题,最开始排查的时候竟然还花了一小会才定位到问题,结果也让我多少有点哭笑不得,也算是一个小知识点吧。
问题描述:
需求是将个数据来源中,一个相同的属性进行合并去除重复,而结果中显示的内容是比预期要少,也就是出现了漏掉一部分熟悉的情况,而我看了一圈代码没有发现问题,这里简单贴一下代码:
func TestInterfaceSplit(t *testing.T) {
strA := []interface{}{"a", "b"}
strB := []interface{}{"b", "c"}
strA = append(strA, strB)
t.Log(removeDuplicates(strA))
/*
输出结果:
[a b]
预期结果:
[a b c]
*/
}
func removeDuplicates(interfaceSplit []interface{}) (strSplit []string) {
strMap := make(map[string]uint)
for _, value := range interfaceSplit {
str, ok := value.(string)
if !ok {
continue
}
strMap[str] = 0
}
for key := range strMap {
strSplit = append(strSplit, key)
}
return
}
排查过程:
因为原本业务中稍微有一些复杂,所以首先排查了一下功能逻辑,一个拼接,一个利用map的hash特性进行去重也很简单,所以检查了一下数据输入,结果发现数据来源没有问题,于是为又回头看了一下代码,突然一拍脑袋,原来问题在这里,[]interface这个切片的问题!
原因:
在go语言中,interface可以理解为是所有类型的父接口,而在这里,因为来源的问题,所以使用了[]interface作为一个统一处理的位置,问题就出现了append这里,因为[]interface也被认为是一个interface本身了,所以实际上过程中出现了一个小错误,代码解释一下:
strA := []interface{}{"a", "b"}
strB := []interface{}{"a", "b", "c"}
strA = append(strA, strB)
// str--> [a b [a b c]],问题就出在了这个里,结果不是预期的[a b a b c],第三个元素是strB本身,所以在去重时,因为类型的边界检查给跳过,而有没有一个好的log来记录过程,所以没有第一时间定位到问题。
解决方法也比较简单,就是在append给一个[]interface时,如果是想append内容,而不是一个切片本身的话,可以使用语法糖进行打散操作:
strA = append(strA, strB...) // ...在go中可以起到一个打散的作用
t.Log(strA) // [a b a b c]
一个很简单的小问题,但是也是很基础的问题,简单记录一下。