golang实现切片

切片

//定义切片类型
type Slice struct {
	// void * C语言中的万能指针,没有具体数据类型,不能进行运算
	Data unsafe.Pointer  //go语言中万能指针类型。操作需要转换成int
	Len int				//数据元素个数
	Cap int				//可扩展的有效容量
}
unsafe.Pointer参与运算操作需要转换,
p := uintptr(unsafep)

申请内存

int main(void)
{
	//申请内存
	int *p = (int *)malloc(100);
	*p = 666
	
	//扩展内存空间
	int *q = realloc(p, 200);

	//释放内存空间
	free(p);
	return 0
}

在go语言中使用c代码

/*
#include 
*/

切片对象操作方法
1.创建切片Create(长度,容量,数据)
2.打印切片Print()
3.追加元素Append(数据)
4.获取元素GetData(下标) int
5.查找元素SearchData(数据) 下标
6.删除元素Delete(下标)
7.销毁切片Destroy()
8.插入元素Insert(数据,下标)

go实现方法

创建切片

func (s *Slice) Create(l int, c int, Data ...int) {
	//1.容错处理,加强代码健壮性
	if s == nil || Data == nil {
		return
	}
	if len(Data) == 0 {
		return
	}
	if l < 0 || c < 0 || l > c || len(Data) > l {
		return
	}
	//2.申请内存空间
	s.Data = C.malloc(C.size_t(c) * 8)

	//3.初始化长度和容量
	s.Len = l
	s.Cap = c

	//4.将s.Data转换成可以计算的数值(地址)
	p := uintptr(s.Data)

	//5.根据Data集合,遍历存入申请的内存中
	for _, v:= range Data {
		*(*int)(unsafe.Pointer(p)) = v
		//指针偏移8
		p += 8
	}
}

打印切片

func (s *Slice) Print() {
	if s == nil {
		return
	}
	//将地址转换为可以计算的数值
	p := uintptr(s.Data)
	//循环打印
	for i := 0; i < s.Len; i++ {
		fmt.Print(*(*int)(unsafe.Pointer(p)), " ")
		p += TAG
	}
	fmt.Println()
}

追加元素

func (s *Slice) Append(Data ...int) {
	if s == nil {
		return
	}
	// 判断是否需要扩容
	for len(Data)+s.Len > s.Cap {
		// 拓展容量为原来的 2 倍, 存储新内存空间地址
		s.Data = C.realloc(s.Data, C.size_t(s.Cap)*2*8)
		s.Cap *= 2
	}
	// 将s.Data 转换程可以运算的 数值
	p := uintptr(s.Data)

	/*	for i:=0; i

根据下标获取元素

//根据切片下标取元素
func (s *Slice) GetData(index int) int {
	if s == nil {
		return -1
	}
	if index < 0 || index >= s.Len {
		return -1
	}
	// 将 万能指针转换为可以计算的 数据
	p := uintptr(s.Data)

	// 偏移p,到 index 指代的元素位置
	p += uintptr(index) * TAG

	// 取数据值,返回
	return *(*int)(unsafe.Pointer(p))
}

已知元素,获取下标

// 已知元素,返回下标值
func (s *Slice) SearchData(Data int) int {
	if s == nil {
		return -1
	}
	// 将万能指针,转换为可以计算的数据值
	p := uintptr(s.Data)

	for i := 0; i < s.Len; i++ {
		if *(*int)(unsafe.Pointer(p)) == Data {
			return i
		}
		p += TAG
	}
	return -1
}

根据下标,删除切片元素

// 根据下标,删除切片元素
func (s *Slice) Delete(index int) {
	if s == nil {
		return
	}
	if index < 0 || index >= s.Len {
		return
	}
	// 将万能指针,转换为可以计算的数据值
	p := uintptr(s.Data)

	// 将p 偏移到 index 位置
	p += uintptr(index) * TAG

	// 定义 变量,记录 p 指代的元素的 下一个元素
	aftp := p

	// 循环从 index 到 s.Len 依次完成 后一个元素给前一个元素赋值
	for i := index; i < s.Len; i++ {
		aftp += TAG
		*(*int)(unsafe.Pointer(p)) = *(*int)(unsafe.Pointer(aftp))
		p += TAG
	}
	// 修改 s.Len 去除一个元素
	s.Len -= 1
}

插入元素

// 根据index ,向 切片插入数据
func (s *Slice) Insert(Data int, index int) {
	if s == nil {
		return
	}
	if index < 0 || index > s.Len {
		return
	}
	// 如果 插入的index 在切片结尾
	if index == s.Len {
		s.Append(Data)
		return
	}

	// 判断是否超出cap

	// 如果插入位置 在 中间
	p := uintptr(s.Data)

	// 将p偏移到 index 位置
	p += uintptr(index) * TAG

	// 获取插入元素完成后的,最后一个元素位置.
	temp := uintptr(s.Data) + uintptr(s.Len) * TAG

	// 循环将 index 之后的元素依次后移(前一个元素,给后一个元素赋值)
	for i := s.Len; i > index; i-- {
		*(*int)(unsafe.Pointer(temp)) = *(*int)(unsafe.Pointer(temp-TAG))
		temp -= TAG
	}

	// 循环结束后,将 p 对应的内存,写入 参数 Data
	*(*int)(unsafe.Pointer(p)) = Data

	// 修改 s.Len
	s.Len++
}

销毁切片 Destroy

  1. 调用 C.free(s.Data) 释放内存空间
  2. 置nil , 驱使 Go语言的 GC工作。
// 销毁 切片
func (s *Slice) Destroy() {
	if s == nil || s.Data == nil {
		return
	}
	C.free(s.Data)
	s.Data = nil		// 驱使go GC工作
	s.Len = 0
	s.Cap = 0
	s = nil

	runtime.GC()		// 手动调用 GC
}

你可能感兴趣的:(数据结构,golang复合数据类型)