Go语言中使用切片(slice)实现一个Vector容器
Go语言中的切片(slice)和一些内置函数能实现其他语言容器类Array、Vector的功能,但是Go内置语言包container里只提供了list、heap、ring三种容器,缺少vector容器,在实际的项目中为使用方便有必要包装一个vector,提供vector的常见功能。
C++、Java、C#等语言支持泛型,Go语言不支持泛型,可以用 interface{} 提供类似泛型的支持。下面是vector容器代码
package vector import (
"reflect"
) // 小写 只能通过工厂函数创建
type vector struct {
values []interface{}
} // 创建工厂函数
func New(cap int) *vector {
this := new(vector)
this.values = make([]interface{}, 0, cap) return this
} func (this *vector) IsEmpty() bool {
return len(this.values) == 0
} // 元素数量
func (this *vector) Size() int {
return len(this.values)
} // 追加单个元素
func (this *vector) Append(value interface{}) bool {
this.values = append(this.values, value)
return true
} // 追加元素切片
func (this *vector) AppendAll(values []interface{}) bool {
if values == nil || len(values) < 1 {
return false
}
this.values = append(this.values, values...)
return true
} // 插入单个元素
func (this *vector) Insert(index int, value interface{}) bool {
if index < 0 || index >= len(this.values) {
return false
}
this.values = append(this.values[:index], append([]interface{}{value}, this.values[index:]...)...)
return true
} // 插入元素切片
func (this *vector) InsertAll(index int, values []interface{}) bool {
if index < 0 || index >= len(this.values) || values == nil || len(values) < 1 {
return false
}
this.values = append(this.values[:index], append(values, this.values[index:]...)...)
return true
} // 移除
func (this *vector) Remove(index int) bool {
if index < 0 || index >= len(this.values) {
return false
}
// 重置为 nil 防止内存泄漏
this.values[index] = nil
this.values = append(this.values[:index], this.values[index+1:]...)
return true
} // 范围移除 从 fromIndex(包含) 到 toIndex(不包含) 之间的元素
func (this *vector) RemoveRange(fromIndex, toIndex int) bool {
if fromIndex < 0 || fromIndex >= len(this.values) || toIndex > len(this.values) || fromIndex > toIndex {
return false
}
// 重置为 nil 防止内存泄漏
for i := fromIndex; i < toIndex; i++ {
this.values[i] = nil
}
this.values = append(this.values[:fromIndex], this.values[toIndex:]...)
return true
} // 全部移除
func (this *vector) RemoveAll() {
// 重置为 nil 防止内存泄漏
for i := 0; i < this.Size(); i++ {
this.values[i] = nil
}
this.values = this.values[0:0]
} func (this *vector) getIndex(value interface{}) int {
for i := 0; i < len(this.values); i++ {
if reflect.DeepEqual(this.values[i], value) {
return i
}
}
return -1
} // 是否存在该元素值
func (this *vector) Contains(value interface{}) bool {
return this.getIndex(value) >= 0
} // 获取元素值第一次出现的索引
func (this *vector) IndexOf(value interface{}) int {
return this.getIndex(value)
} // 获取元素值最后一次出现的索引
func (this *vector) LastIndexOf(value interface{}) int {
for i := len(this.values) - 1; i >= 0; i-- {
if reflect.DeepEqual(this.values[i], value) {
return i
}
}
return -1
} // 得到索引对应的元素值
func (this *vector) GetValue(index int) interface{} {
if index < 0 || index >= len(this.values) {
return nil
}
return this.values[index]
} // 设置值
func (this *vector) SetValue(index int, value interface{}) bool {
if index < 0 || index >= len(this.values) {
return false
}
this.values[index] = value
return true
} func (this *vector) ToArray() []interface{} {
dst := make([]interface{}, this.Size())
copy(dst, this.values)
return dst
}
vector内部使用切片(slice)保存元素值,元素类型 interface{},泛型。getIndex()方法使用reflect.DeepEqual()函数对元素值作深度比较。上述代码只提供了vector容器常见功能,更多的功能可以根据需要添加,比如有的时候需要对容器中的元素排序,则可以添加排序方法。
一些方法简单返回bool值表示成功或失败,可以根据需要增加一个error返回值指明失败的详细原因。
需要注意的事项是Remove、RemoveRange、RemoveAll方法内把元素移走时避免内存泄露。
下面是测试代码
func testVector() {
v := vector.New(5)
for i := 0; i < 6; i++ {
v.Append(i)
}
fmt.Println(*v)
fmt.Println(v.IsEmpty())
v.Insert(1, 10)
v.Insert(20, 20)
fmt.Println(*v)
v.Remove(-1)
v.Remove(1)
v.Remove(100)
fmt.Println(*v)
fmt.Println(v.IndexOf(3))
fmt.Println(v.IndexOf(300))
fmt.Println(v.GetValue(1))
fmt.Println(v.GetValue(100))
v.SetValue(-1, -1)
v.SetValue(1, 11)
v.SetValue(100, 101)
fmt.Println(*v)
v.RemoveAll()
fmt.Println(v.IsEmpty())
fmt.Println(v.Size())
v.Append(22)
fmt.Println(*v)
}
测试代码覆盖了部分可能的情况,创建函数New的cap参数指明容器的初始容量。
上述测试代码只写了int类型的元素,其他string、float、array、map、struct、slice、vector等类型类似。
Go语言中使用切片(slice)实现一个Vector容器的更多相关文章
- Go语言中的切片(十)
go中数组的长度是固定的,且不同长度的数组是不同类型,这样的限制带来不少局限性.于是切片就来了,切片(Slice)是一个拥有相同类型元素的可变长度的序列.它是基于数组类型做的一层封装.它非常灵活,支持 ...
- [Go] gocron源码阅读-go语言中的切片和类型综合
在gocron.go文件的main函数中,有下面这一句,从这句代码中可以学习到切片和类型的综合运用 cliApp.Flags = append(cliApp.Flags, []cli.Flag{}.. ...
- [Go] gocron源码阅读-go语言中的切片接口和类型综合
// getCommands func getCommands() []cli.Command { command := cli.Command{ Name: "web", Usa ...
- Go语言数组和切片的原理
目录 数组 创建 访问和赋值 切片 结构 初始化 访问 追加 拷贝 总结 数组和切片是 Go 语言中常见的数据结构,很多刚刚使用 Go 的开发者往往会混淆这两个概念,数组作为最常见的集合在编程语言中是 ...
- 2.C语言中的关键字
1.auto 修饰局部变量,编译器默认所有局部变量都是用auto来修饰的,所以在程序中很少见到. 2.static 它作用可大了,除了可以修饰变量,还可以修饰函数,修饰变量,改变其作用域和生命周期,修 ...
- go语言的 数组、slice、map使用(转)
golang群 点击加入 go语言的 数组.slice.map使用, 由于网上有很好的说明, 不需要再写了,请看这几篇: Go语言中的 Array, Slice和 Map 深入学习golang五篇,以 ...
- C语言中的结构体,结构体数组
C语言中的结构体是一个小难点,下面我们详细来讲一下:至于什么是结构体,结构体为什么会产生,我就不说了,原因很简单,但是要注意到是结构体也是连续存储的,但要注意的是结构体里面类型各异,所以必然会产生内存 ...
- python 和 R 语言 中的 range() 函数
1.python 中的 range() 函数生成整数序列,常用于 for 循环的迭代. 示例: 2.R 语言中的 range() 函数返回一个数值向量中的最小值和最大中,常用于求极差. 示例: 按语: ...
- C语言中的关键字总结
1.auto 修饰局部变量,编译器默认所有局部变量都是用auto来修饰的,所以在程序中很少见到. 2.static 它作用可大了,除了可以修饰变量,还可以修饰函数,修饰变量,改变其作用域和生命周期,修 ...
随机推荐
- 第82题:删除排序链表中的重复元素II
一. 问题描述 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字. 示例 1: 输入: 1->2->3->3->4->4->5 ...
- Python 12---图形界面
def load(event):f= open(filename.GetValue())contents.SetValue(f.read())f.close() def save(event):new ...
- 评估类模型之优劣解距离法Topsis模型
定义: TOPSIS法是一种常用的综合评价方法,其能充分利用原始数据的信息,其结果能精确地反映各评价方案之间的差距. 层次分析法的局限性: 问题和解决方案: 所以最终评分公式为: 指标正向化,得到正向 ...
- dblclick([[data],fn]) 当双击元素时,会发生 dblclick 事件。
dblclick([[data],fn]) 概述 当双击元素时,会发生 dblclick 事件.大理石量具哪家好 当鼠标指针停留在元素上方,然后按下并松开鼠标左键时,就会发生一次 click.在很短的 ...
- An Introduction to Laravel Policy
An Introduction to Laravel Policy 30 Dec 2018 . Laravel. 7.6K views If you heard about Laravel Polic ...
- Luogu5369 [PKUSC2018]最大前缀和
题目链接:洛谷 题目大意:给定一个长为$n$的整数序列,求全排列的最大前缀和(必须包含第一个数)之和. 数据范围:$1\leq n\leq 20,1\leq \sum_{i=1}^n|a_i|\leq ...
- Linux配置Tomcat8080端口 远程无法访问解决办法
是因为Linux的防火墙没有开放8080端口 解决办法: /sbin/iptables -I INPUT -p tcp --dport 8080 -j ACCEPT #开启8080端口 /sbin/ ...
- MySQL服务器基准测试
一.基准测试简介 1.什么是基准测试 数据库的基准测试是对数据库的性能指标进行定量的.可复现的.可对比的测试. 基准测试与压力测试 基准测试可以理解为针对系统的一种压力测试.但基准测试不关心业务逻辑, ...
- k8s/Kubernetes常用组件Helm的部署
Helm的安装 1.Helm的基本概念 Helm是Kubernetes的一个包管理工具,用来简化Kubernetes应用的部署和管理.可以把Helm比作CentOS的yum工具. Helm有如下几个基 ...
- hive 常用参数
hive.exec.max.created.files •说明:所有hive运行的map与reduce任务可以产生的文件的和 •默认值:100000 hive.exec.dynamic.partit ...