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结构体嵌套的切片数组操作
Apr 28 Golang
解决Golang中goroutine执行速度的问题
May 02 Golang
go设置多个GOPATH的方式
May 05 Golang
Golang: 内建容器的用法
May 05 Golang
使用golang编写一个并发工作队列
May 08 Golang
golang 实用库gotable的具体使用
Jul 01 Golang
Go语言基础知识点介绍
Jul 04 Golang
go使用Gin框架利用阿里云实现短信验证码功能
Aug 04 Golang
Go语言的协程上下文的几个方法和用法
Apr 11 Golang
golang用type-switch判断interface的实际存储类型
Apr 14 Golang
golang定时器
Apr 14 Golang
Golang 实现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
《Pokemon Sword·Shield》系列WEB动画《薄明之翼》第2话声优阵容公开!
2020/03/06 日漫
php 全文搜索和替换的实现代码
2008/07/29 PHP
PHP的可变变量名的使用方法分享
2012/02/05 PHP
解析MySql与Java的时间类型
2013/06/22 PHP
基于ThinkPHP+uploadify+upload+PHPExcel 无刷新导入数据
2015/09/23 PHP
php写入txt乱码的解决方法
2019/09/17 PHP
利用JQuery和JS实现奇偶行背景颜色自定义效果
2012/11/19 Javascript
探讨JQUERY JSON的反序列化类 using问题的解决方法
2013/12/19 Javascript
jQuery中prevUntil()方法用法实例
2015/01/08 Javascript
window.open()实现post传递参数
2015/03/12 Javascript
JavaScript中使用Math.PI圆周率属性的方法
2015/06/14 Javascript
Node.js DES加密的简单实现
2016/07/07 Javascript
微信小程序 form组件详解
2016/10/25 Javascript
从parcel.js打包出错到选择nvm的全部过程
2018/01/23 Javascript
解决vue2.0路由跳转未匹配相应用路由避免出现空白页面的问题
2018/08/24 Javascript
JavaScript 作用域实例分析
2019/10/02 Javascript
Python pickle模块用法实例
2015/04/14 Python
Python入门学习之字符串与比较运算符
2015/10/12 Python
Python数据结构之顺序表的实现代码示例
2017/11/15 Python
python消除序列的重复值并保持顺序不变的实例
2018/11/08 Python
Python爬虫库BeautifulSoup的介绍与简单使用实例
2020/01/25 Python
css3实现超立体3D图片侧翻倾斜效果
2014/04/16 HTML / CSS
Elemis美国官网:英国的第一豪华护肤品牌
2018/03/15 全球购物
一个精品风格的世界:Atterley
2019/05/01 全球购物
介绍一下Java的事务处理
2012/12/07 面试题
程序员岗位职责
2013/11/11 职场文书
复核员上岗演讲稿
2014/01/05 职场文书
酒后驾驶检讨书
2014/01/27 职场文书
房屋租赁协议书
2014/10/18 职场文书
学校元旦晚会开场白
2014/12/14 职场文书
仓库保管员岗位职责
2015/02/09 职场文书
2015仓库保管员年终工作总结
2015/05/13 职场文书
2016年暑期见闻作文
2015/11/25 职场文书
一波干货,会议主持词开场白范文
2019/05/06 职场文书
教你解决往mysql数据库中存入汉字报错的方法
2021/05/06 MySQL
图文详解matlab原始处理图像几何变换
2021/07/09 Python