slice 实现原理

2022-10-12,

package main

/*
#include <stdlib.h>
 */
import "c"
import (
	"unsafe"
	"fmt"
)

type slice struct {
	data unsafe.pointer //万能指针类型 对应c语言中的void*
	len  int            //有效的长度
	cap  int            //有效的容量
}

const tag = 8

/*
func main() {
	//定义一个切片
	//1、数据内存地址 2、len 有效数据长度 3、cap 可扩容的有效容量  24字节
	var s []int

	//unsafe.sizeof 计算数据类型在内存中占的字节大小
	fmt.println(unsafe.sizeof(s))
}
*/
/*
func main(){
	var i interface{}
	i=10//只支持== !=

	//类型断言  是基于接口类型数据的转换
	//value,ok:=i.(int)
	//if ok{
	//	fmt.println("整型数据:",value)
	//	fmt.printf("%t\n",value)
	//}
	//反射获取接口的数据类型
	//t:=reflect.typeof(i)
	//fmt.println(t)

	//反射获取接口类型数据的值
	v:=reflect.valueof(i)
	fmt.println(v)

	i1:=10
	i2:=20

	if reflect.typeof(i1)==reflect.typeof(i2){
		v1:=reflect.valueof(i1)
		v2:=reflect.valueof(i2)
		结果=v1+v2
	}
}
*/
//create(长度 容量 数据)
func (s *slice) create(l int, c int, data ...int) {
	//如果数据为空返回
	if len(data) == 0 {
		return
	}
	//长度小于0 容量小于0 长度大于容量 数据大于长度
	if l < 0 || c < 0 || l > c || len(data) > l {
		return
	}
	//ulonglong unsigned long long  无符号的长长整型
	//通过c语言代码开辟空间 存储数据
	//如果堆空间开辟失败 返回值为null 相当于nil 内存地址编号为0的空间
	s.data = c.malloc(c.ulonglong(c) * 8)
	s.len = l
	s.cap = c

	//转成可以计算的指针类型
	p := uintptr(s.data)
	for _, v := range data {
		//数据存储
		*(*int)(unsafe.pointer(p)) = v
		//指针偏移
		p += tag
		//p+=unsafe.sizeof(1)
	}
}

//print 打印切片
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
	}

}

//切片追加
func (s *slice) append(data ...int) {
	if s == nil {
		return
	}
	if len(data) == 0 {
		return
	}

	//如果添加的数据超出了容量
	if s.len+len(data) > s.cap {
		//扩充容量
		//c.realloc(指针,字节大小), go 语言 2 倍扩容。
		s.data = c.realloc(s.data, c.ulonglong(s.cap)*2*8)
		//改变容量的值
		s.cap = s.cap * 2
	}

	p := uintptr(s.data)
	for i := 0; i < s.len; i++ {
		//指针偏移
		p += tag
	}

	//添加数据
	for _, v := range data {
		*(*int)(unsafe.pointer(p)) = v
		p += tag
	}
	//更新有效数据(长度)
	s.len = s.len + len(data)
}

//获取元素 getdata(下标)  返回值为int 元素
func (s *slice) getddata(index int) int {
	if s == nil || s.data == nil {
		return 0
	}
	if index < 0 || index > s.len-1 {
		return 0
	}

	p := uintptr(s.data)
	for i := 0; i < index; i++ {
		p += tag
	}
	return *(*int)(unsafe.pointer(p))
}

//查找元素 search(元素)返回值为int 下标
func (s *slice) search(data int) int {
	if s == nil || s.data == 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
}

//删除元素 delete(下标)
func (s *slice) delete(index int) {
	if s == nil || s.data == nil {
		return
	}
	if index < 0 || index > s.len-1 {
		return
	}

	//将指针指向需要删除的下标位置
	p := uintptr(s.data)
	for i := 0; i < index; i++ {
		p += tag
	}

	//用下一个指针对应的值为当前指针对应的值进行赋值
	temp := p
	for i := index; i < s.len; i++ {
		temp += tag
		*(*int)(unsafe.pointer(p)) = *(*int)(unsafe.pointer(temp))
		p += tag
	}

	s.len--
}

//插入元素 insert(下标 元素)
func (s *slice) insert(index int, data int) {
	if s == nil || s.data == nil {
		return
	}
	if index < 0 || index > s.len-1 {
		return
	}

	//如果插入数据是最后一个
	//if index == s.len-1 {
	//	p := uintptr(s.data)
	//
	//	//for i := 0; i < s.len; i++ {
	//	//	p += tag
	//	//}
	//	p += tag * uintptr(s.len-1)
	//	*(*int)(unsafe.pointer(p)) = data
	//	s.len++
	//	return
	//}
	//调用追加方法
	if index == s.len-1 {
		s.append(data)
		return
	}

	//获取插入数据的位置
	p := uintptr(s.data)
	for i := 0; i < index; i++ {
		p += tag
	}
	//获取末尾的指针位置

	temp := uintptr(s.data)
	temp += tag * uintptr(s.len)

	//将后面数据依次向后移动
	for i := s.len; i > index; i-- {
		//用前一个数据为当前数据赋值
		*(*int)(unsafe.pointer(temp)) = *(*int)(unsafe.pointer(temp - tag))
		temp -= tag
	}

	//修改插入下标的数据
	*(*int)(unsafe.pointer(p)) = data
	s.len++
}

//销毁切片
func (s *slice) destroy() {
	//调用c语言  适释放堆空间
	c.free(s.data)
	s.data = nil
	s.len = 0
	s.cap = 0
	s = nil
}

 

《slice 实现原理.doc》

下载本文的Word格式文档,以方便收藏与打印。