slice 实现原理
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 实现原理的更多相关文章
- golang slice 切片原理
golang 中的 slice 非常强大,让数组操作非常方便高效.在开发中不定长度表示的数组全部都是 slice .但是很多同学对 slice 的模糊认识,造成认为golang中的数组是引用类型,结果 ...
- [js] Array.slice和类数组转数组
a.call(b) 相当于把a方法放到b的原型上(实例私有方法)执行 Array.slice的用途 https://juejin.im/post/5b20b8596fb9a01e8d6a47c0 用法 ...
- slice 切片实现 Slice object interface
1.Python切片对象可以为任意类型 https://github.com/python/cpython/blob/master/Include/sliceobject.h /* Slice obj ...
- 03. Go 语言容器
Go语言容器(container) 变量在一定程度上能满足函数及代码要求.如果编写一些复杂算法.结构和逻辑,就需要更复杂的类型来实现.这类复杂类型一般情况下具有各种形式的存储和处理数据的功能,将它们称 ...
- GO学习笔记 - 数据校验
本文主题:基于asaskevich/govalidator实现Golang数据校验 小慢哥的原创文章,欢迎转载 目录 ▪ 一. asaskevich/govalidator介绍 ▪ 二. 字符串匹配 ...
- 面试官问:Go 中的参数传递是值传递还是引用传递?
一个程序中,变量分为变量名和变量内容,变量内容的存储一般会被分配到堆和栈上.而在 Go 语言中有两种传递变量的方式值传递和引用传递.其中值传递会直接将变量内容附在变量名上传递,而引用传递会将变量内容的 ...
- 深度学习实践-物体检测-faster-RCNN(原理和部分代码说明) 1.tf.image.resize_and_crop(根据比例取出特征层,进行维度变化) 2.tf.slice(数据切片) 3.x.argsort()(对数据进行排列,返回索引值) 4.np.empty(生成空矩阵) 5.np.meshgrid(生成二维数据) 6.np.where(符合条件的索引) 7.tf.gather取值
1. tf.image.resize_and_crop(net, bbox, 256, [14, 14], name) # 根据bbox的y1,x1,y2,x2获得net中的位置,将其转换为14*1 ...
- 【前端基础系列】slice方法将类数组转换数组实现原理
问题描述 在日常编码中会遇到将类数组对象转换为数组的问题,其中常用到的一种方式使用Array.prototype.slice()方法. 类数组对象 所谓的类数组对象,JavaScript对它们定义为: ...
- [转载]Array.prototype.slice.call(arguments,1)原理
Array.prototype.slice.call(arguments,1)该语句涉及两个知识点. arguments是一个关键字,代表当前参数,在javascript中虽然arguments表面上 ...
随机推荐
- tensorflow模型的保存与加载
模型的保存与加载一般有三种模式:save/load weights(最干净.最轻量级的方式,只保存网络参数,不保存网络状态),save/load entire model(最简单粗暴的方式,把网络所有 ...
- STM32学习笔记 —— 0.1 Keil5安装和DAP仿真下载器配置的相关问题与注意事项
Keil5安装的注意事项 安装细节在此不再做过多赘述,主要介绍一下注意事项: 安装路径中不能有中文. ARM的Keil的路径不能与51的Keil的有冲突,必须将目录分开. Keil5中不会自动添加芯片 ...
- PAT (Basic Level) Practice (中文)1031 查验身份证 (15 分)
一个合法的身份证号码由17位地区.日期编号和顺序编号加1位校验码组成.校验码的计算规则如下: 首先对前17位数字加权求和,权重分配为:{7,9,10,5,8,4,2,1,6,3,7,9,10,5,8, ...
- 0级搭建类013-CentOS 8.x 安装
CentOS 8 操作系统安装
- IDEA常用的几个插件
目录 1. 阿里巴巴代码检测插件 2. Json转Pojo插件 3. mybatis辅助插件 4. 翻译插件 5. markdown插件 6. RestfulToolKit插件 IDEA常用插件 1. ...
- Java连载76-基础数据类型包装类型及其方法简介
一.java中八种基本数据类型对应的包装类型 基本数据类型 包装类型 byte java.lang.Byte short ...
- 数据预处理 | 通过 Z-Score 方法判断异常值
判断异常值方法:Z-Score 计算公式 Z = (X-μ)/σ 其中μ为总体平均值,X-μ为离均差,σ表示标准差.z的绝对值表示在标准差范围内的原始分数与总体均值之间的距离.当原始分数低于平均值时, ...
- day30 nfs服务器配置
04. NFS服务部署流程 RPC: 远程过程调用服务程序--- 相当于租房的中介(网络编程支持) 服务端部署 第一个历程: 下载安装软件 rpm -qa|grep -E "nfs|rpc& ...
- 《深入理解java虚拟机》读书笔记十——第十一章
第十一章 晚期(运行期)优化 1.HotSpot虚拟机内的即时编译 解释器与编译器: 许多Java虚拟机的执行引擎在执行Java代码的时候都有解释执行(通过解释器执行)和编译执行(通过即时编译器产生 ...
- Vue中常见参数传递方式
文章内容:这里只有vue中父子组件传参.路由间的传参 (另外还有vuex.储存本地.中央bus等方式) 一.父子组件 1.1父传子(props) <!-- 父组件father.vue --> ...