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 相关文章推荐
golang判断key是否在map中的代码
Apr 24 Golang
go原生库的中bytes.Buffer用法
Apr 25 Golang
golang DNS服务器的简单实现操作
Apr 30 Golang
Golang Gob编码(gob包的使用详解)
May 07 Golang
Go 在 MongoDB 中常用查询与修改的操作
May 07 Golang
Go语言空白表示符_的实例用法
Jul 04 Golang
golang中字符串MD5生成方式总结
Jul 04 Golang
Go语言安装并操作redis的go-redis库
Apr 14 Golang
golang语言指针操作
Apr 14 Golang
Golang获取List列表元素的四种方式
Apr 20 Golang
Golang ort 中的sortInts 方法
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利用smtp类实现电子邮件发送
2015/10/30 PHP
PHP简单判断字符串是否包含另一个字符串的方法
2016/03/25 PHP
php 解决substr()截取中文字符乱码问题
2016/07/18 PHP
Yii框架的路由配置方法分析
2019/09/09 PHP
自动更新作用
2006/10/08 Javascript
关于jquery ajax 调用带参数的webservice返回XML数据一个小细节
2012/07/31 Javascript
纯js实现瀑布流展现照片(自动适应窗口大小)
2013/04/08 Javascript
js触发select onchange事件的小技巧
2014/08/05 Javascript
基于JavaScript怎么实现让歌词滚动播放
2015/11/03 Javascript
Javascript如何判断数据类型和数组类型
2016/06/22 Javascript
jQuery右下角悬浮广告实例
2016/10/17 Javascript
Windows系统下安装Node.js的步骤图文详解
2016/11/15 Javascript
jQuery中hover方法搭配css的hover选择器,实现选中元素突出显示方法
2017/05/08 jQuery
vux-scroller实现移动端上拉加载功能过程解析
2019/10/08 Javascript
[03:24][TI9纪实] Dota奶爸
2019/08/22 DOTA
详解Python中dict与set的使用
2015/08/10 Python
Python获取当前页面内所有链接的四种方法对比分析
2017/08/19 Python
Python调用服务接口的实例
2019/01/03 Python
python 实现将文件或文件夹用相对路径打包为 tar.gz 文件的方法
2019/06/10 Python
python 模拟银行转账功能过程详解
2019/08/06 Python
Python爬虫:将headers请求头字符串转为字典的方法
2019/08/21 Python
Python + Requests + Unittest接口自动化测试实例分析
2019/12/12 Python
Python判断字符串是否为空和null方法实例
2020/04/26 Python
HTML5 3D衣服摇摆动画特效
2016/03/17 HTML / CSS
欧克利英国官网:Oakley英国
2019/08/24 全球购物
请编写一个 C 函数,该函数在给定的内存区域搜索给定的字符,并返回该字符所在位置索引值
2014/09/15 面试题
银行毕业实习自我鉴定
2013/09/19 职场文书
机械设计专业应届生求职信
2013/11/21 职场文书
英文求职信写作小建议
2014/02/16 职场文书
家长通知书教师评语
2014/04/17 职场文书
入党积极分子学习优秀共产党员先进事迹思想汇报
2014/09/13 职场文书
2016春季幼儿园大班开学寄语
2015/12/03 职场文书
python关于集合的知识案例详解
2021/05/30 Python
怎么禁用Windows 11快照布局? win11不使用快照布局的技巧
2021/11/21 数码科技
vue3使用vuedraggable实现拖拽功能
2022/04/06 Vue.js
python实现商品进销存管理系统
2022/05/30 Python