go语言求任意类型切片的长度操作


Posted in Golang onApril 26, 2021

最近用go写程序时遇到一个问题——求任意类型切片的长度。

作为一个初学者,刚刚学了接口和切片,知道了每个类型都实现了一个空接口interface{},那么如果接口类型作为函数的参数,那它应该是可以接收任意类型的实参的

带着这样的想法就写出了下面的代码:

func size(ins []interface{}) int {
        return len(ins)
}

然后调用

a := []int{1, 2, 3, 4}
fmt.Println(size(a))

但编译的时候报了以下错误:

cannot use a (type []int) as type []interface {} in argument to size

从报错的信息来看,是go语言不支持将任意类型的切片转换为接口切片所导致的,为了确定是go语言本身不支持所导致以及探究不支持的原因,于是在网上查阅了一些资料,最权威的应该是来自于go的官方文档

这上边的解释是说,由于非接口类型的切片与接口类型的切片在内存中的空间布局不一样,如果要做这样的隐式转换,将会比较耗时,因此go不支持此种转换。

如果确实需要用到传接口切片的情况,则需要由程序员自己来提前做转换,在传参的时候确保实参是接口切片类型,这样才能通过编译,这也是官方推荐的做法

代码如下所示:

// 获得一个int类型的切片
var dataSlice []int = foo()
// 创建接口类型的切片
var interfaceSlice []interface{} = make([]interface{}, len(dataSlice))
// 依次转换每个元素
for i, d := range dataSlice {
 interfaceSlice[i] = d
}
// 调用上面的size方法
size(interfaceSlice)

如果按照上面的写法来传参,那么求切片的长度就显得太费劲了,还不如直接调用 len(dataSlice) 完事。

事情发展到这里,有点不甘心,于是继续查资料,发现go语言的反射机制可以解决这个问题。

首先将上面的size函数的参数改为接口类型(a interface{}),然后在里面用reflect.TypeOf(a).Kind()来判断实参的类型,如果是切片类型,则用reflect.ValueOf()来获得该切片,最后返回切片的长度

代码如下所示:

func Size(a interface{}) int {
        if reflect.TypeOf(a).Kind() != reflect.Slice {
                return -1
        }
        ins := reflect.ValueOf(a)
        return ins.Len()
}

补充:Go语言中切片的长度与容量的变化

在学习go语言的切片信息时,发现切片的容量变化非常让人摸不着头脑,为了更记忆深刻就写下了这篇,如有错误之处,请大家指正

一、当前切片的长度与容量相等情况:

package main
import (
    "fmt"
)
func main() {
	numbers := []int{0,1,2}  
	printSlice(numbers)
	//通过append给numbers增加信息,如果当前切片的长度与容量相等,增加信息的长度小于等于原来的长度,
	那么切片的长度变为相加之和,容量变为原来的2倍(图片一的第二行结果)
	numbers = append(numbers, 10,5,6) 
	printSlice(numbers)
	
	//通过append给numbers增加信息,如果当前切片A的长度与容量相等,增加信息B的长度大于切片A原来的长度,
	那么切片的长度变为相加之和,容量变为:B长度+A长度+(B长度-A长度)%2(图片一的第三行结果)
	numbers = append(numbers, 12,13,15,16,17,18,19,20,21,22,23) 
	printSlice(numbers)
}
func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}

图片一:

go语言求任意类型切片的长度操作

二、如果当前切片的长度小于容量情况:

1、增加信息的长度与当前长度和小于等于容量

func main() {
   /* 创建切片 */
   numbers := []int{0,1,2}  
   printSlice(numbers)
   numbers = append(numbers, 10,5) 
   printSlice(numbers)
   //通过append给numbers增加信息,如果当前切片的长度小于容量,增加信息的长度与当前长度和小于等于容量,
   那么numbers的长度变为相加之和,容量不变(图片二的第三行结果)
   numbers = append(numbers, 11)  
   printSlice(numbers)
}

图片二:

go语言求任意类型切片的长度操作

2、增加信息B的长度与当前A的长度大于A容量并且小于A容量的2倍

func main() {
   /* 创建切片 */
   numbers := []int{0,1,2}  
   printSlice(numbers)
   numbers = append(numbers, 10,5) 
   printSlice(numbers)
   //通过append给numbers增加信息,如果当前切片A的长度小于容量,增加信息B的长度与当前A的长度大于A容量并且小于A容量的2倍,
   那么numbers的长度变为相加之和,容量变为:A容量*2(图片三的第三行结果)
   numbers = append(numbers, 11,12)  
   printSlice(numbers)
}

图片三:

go语言求任意类型切片的长度操作

3、增加信息B的长度与当前A的长度大于A容量的2倍

func main() {
	/* 创建切片 */
	numbers := []int{0,1,2}  
	printSlice(numbers)
	numbers = append(numbers, 10,5) 
	printSlice(numbers)
	//通过append给numbers增加信息,如果当前切片A的长度小于容量,增加信息B的长度与当前A的长度大于A容量的2倍,
	那么numbers的长度变为相加之和C。容量变为:B长度+A长度+(B长度-A长度)%2(图片四的第三行结果)
	numbers = append(numbers, 11,12,13,15,16,17,18,19,20)  
	printSlice(numbers)
}

图片四:

go语言求任意类型切片的长度操作

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。如有错误或未考虑完全的地方,望不吝赐教。

Golang 相关文章推荐
基于go interface{}==nil 的几种坑及原理分析
Apr 24 Golang
Go语言切片前或中间插入项与内置copy()函数详解
Apr 27 Golang
go结构体嵌套的切片数组操作
Apr 28 Golang
Go语言中break label与goto label的区别
Apr 28 Golang
解决Golang中goroutine执行速度的问题
May 02 Golang
Golang之sync.Pool使用详解
May 06 Golang
go语言中fallthrough的用法说明
May 06 Golang
使用golang编写一个并发工作队列
May 08 Golang
基于Go语言构建RESTful API服务
Jul 25 Golang
如何解决goland,idea全局搜索快捷键失效问题
Apr 03 Golang
Golang 实现WebSockets
Apr 24 Golang
Golang 实现 WebSockets 之创建 WebSockets
Apr 24 Golang
golang如何去除多余空白字符(含制表符)
Apr 25 #Golang
用golang如何替换某个文件中的字符串
Apr 25 #Golang
Golang 正则匹配效率详解
golang正则之命名分组方式
Apr 25 #Golang
go语言-在mac下brew升级golang
Apr 25 #Golang
go原生库的中bytes.Buffer用法
Apr 25 #Golang
Go缓冲channel和非缓冲channel的区别说明
Apr 25 #Golang
You might like
php 三维饼图的实现代码
2008/09/28 PHP
php垃圾代码优化操作代码
2010/08/05 PHP
使用php显示搜索引擎来的关键词
2014/02/13 PHP
Laravel中注册Facades的步骤详解
2016/03/16 PHP
php通过curl添加cookie伪造登陆抓取数据的方法
2016/04/02 PHP
php 输入输出流详解及示例代码
2016/08/25 PHP
PHP中抽象类,接口功能、定义方法示例
2019/02/26 PHP
javascript+dom树型菜单类,希望朋友们一起进步
2007/05/03 Javascript
Jquery中ajax方法data参数的用法小结
2014/02/12 Javascript
详细分析JavaScript变量类型
2015/07/08 Javascript
jQuery插件formValidator自定义函数扩展功能实例详解
2015/11/25 Javascript
Js删除数组中某一项或几项的几种方法(推荐)
2016/07/27 Javascript
jQuery.ajax实现根据不同的Content-Type做出不同的响应
2016/11/03 Javascript
详解Vue打包优化之code spliting
2018/04/09 Javascript
JS Object.preventExtensions(),Object.seal()与Object.freeze()用法实例分析
2018/08/25 Javascript
jQuery实现侧边栏隐藏与显示的方法详解
2018/12/22 jQuery
JavaScript创建防篡改对象的方法分析
2018/12/30 Javascript
vue19 组建 Vue.extend component、组件模版、动态组件 的实例代码
2019/04/04 Javascript
[03:03]2014DOTA2西雅图国际邀请赛 Alliance战队巡礼
2014/07/07 DOTA
[47:46]完美世界DOTA2联赛 Magma vs GXR 第三场 11.07
2020/11/10 DOTA
python中dir函数用法分析
2015/04/17 Python
Python实现的插入排序算法原理与用法实例分析
2017/11/22 Python
python绘制条形图方法代码详解
2017/12/19 Python
Python实现对特定列表进行从小到大排序操作示例
2019/02/11 Python
深入解析python中的实例方法、类方法和静态方法
2019/03/11 Python
Django如何防止定时任务并发浅析
2019/05/14 Python
利于python脚本编写可视化nmap和masscan的方法
2020/12/29 Python
详解HTML5 window.postMessage与跨域
2017/05/11 HTML / CSS
理肤泉俄罗斯官网:La Roche-Posay俄罗斯
2018/07/24 全球购物
同程旅游英文网站:LY.com
2018/11/13 全球购物
美国豪华的多品牌精品店:The Webster
2019/07/31 全球购物
英国设计师珠宝网站:Joshua James Jewellery
2020/03/01 全球购物
体育专业求职信
2014/07/16 职场文书
篮球友谊赛通讯稿
2014/10/10 职场文书
《游戏王:大师决斗》新活动上线 若无符合卡组可免费租用
2022/04/13 其他游戏
Go本地测试解耦任务拆解及沟通详解Go本地测试的思路沟通的重要性总结
2022/06/21 Golang