当前位置: 首页 > news >正文

【GoLang】切片的面试知识点

nil切片 和 空切片

nil切片是只声明但未初始化,没有分配底层数组的内存空间,

空切片是初始化了的,有分配数组内存,只是数组内没有元素。

二者都可以正常扩容、遍历。不会报错。

append 如何添加切片

append 可以增加切片,通过在切片后面加上...,就可以进行添加。

如何比较两个切片是否相等,判断依据是什么

判断依据:1. 切片长度;  2. 切片指向数组的所有元素

只要两个切片的长度相等并且指向数组内所有元素及顺序都相等,那么两个切片就相等。两个数组可以不是同一个数组。

判断函数:

1. reflect.DeepEqual()

2. 自定义函数

使用[a:b]对切片进行截取

使用[a:b]对切片进行截取得到的新切片,新切片的长度是 b-a,容量是 底层数组长度-a 。新切片与旧切片共用一个底层数组

拷贝大切片一定比小切片代价大吗?

切片是对底层数组的一个轻量级抽象,切片本身由三个字段组成:指向底层数组的指针、切片的长度(len)和容量(cap)。因此,将一个切片赋值给另一

个切片变量,或在函数间传递切片时,仅仅是复制这三个字段的值,并不会复制底层数组的实际数据。

此时,无论切片引用的底层数组有多大,复制切片的开销都是恒定的,因为只涉及三个字段的复制。

但是,如果使用copy 实现深拷贝,则底层数组也会被拷贝,此时拷贝大切片比拷贝小切片代价更大

如何将自定义类型切片转字节切片,以及字节切片转回自定义类型切片?

package mainimport ("bytes""encoding/binary""fmt"
)type MyType struct {A int32B float64
}// 将任意类型切片转换为byte切片
func MyTypeSliceToByteSlice(data []MyType) ([]byte, error) {buf := new(bytes.Buffer)     // 创建字节缓冲区 buf,用于存储序列化后的字节数据。for _, value := range data { // 遍历自定义类型切片if err := binary.Write(buf, binary.LittleEndian, value); err != nil {// 将自定义类型切片的元素Value 以小端字节序的形式LittleEndian 写进buf中// 小端字节序:指数值的低位字节存储在内存的低地址处。例如,数值0x1234在小端序下会被存储为0x34, 0x12。大端序存储为:0x12, 0x34。return nil, err}}return buf.Bytes(), nil
}func main() {data := []MyType{{A: 1, B: 2.5},{A: 3, B: 4.7},}fmt.Println("[]myType-->", data)bytes, err := MyTypeSliceToByteSlice(data)if err != nil {fmt.Println("Error:", err)return}fmt.Println("[]byte-->", bytes)}

// 将byte切片转换为任意类型切片
func ByteSliceToMyTypeSlice(data []byte) ([]MyType, error) {buf := bytes.NewReader(data) // 将输入的字节切片data包装成一个只读的缓冲区buf。可以方便地按顺序读取字节,无需关心底层的字节切片操作。fmt.Println("buf-->", buf)var result []MyTypefor buf.Len() > 0 {var value MyType // value表示 []MyType 的元素if err := binary.Read(buf, binary.LittleEndian, &value); err != nil {// 从缓冲区buf中 以小段字节序LittleEndian的形式 读取数据到value中return nil, err}result = append(result, value) // 将value添加进 []MyType 中}return result, nil
}

综合案例

package mainimport ("bytes""encoding/binary""fmt"
)type MyType struct {A int32B float64
}func MyTypeSliceToByteSlice(data []MyType) ([]byte, error) {buf := new(bytes.Buffer)     // 创建字节缓冲区 buf,用于存储序列化后的字节数据。for _, value := range data { // 遍历自定义类型切片if err := binary.Write(buf, binary.LittleEndian, value); err != nil {// 将自定义类型切片的元素Value 以小端字节序的形式LittleEndian 写进buf中// 小端字节序:指数值的低位字节存储在内存的低地址处。例如,数值0x1234在小端序下会被存储为0x34, 0x12。大端序存储为:0x12, 0x34。return nil, err}}return buf.Bytes(), nil
}func main() {data := []MyType{{A: 1, B: 2.5},{A: 3, B: 4.7},}fmt.Println("[]myType-->", data)bytes, err := MyTypeSliceToByteSlice(data)if err != nil {fmt.Println("Error:", err)return}fmt.Println("[]byte-->", bytes)myTypes, err := ByteSliceToMyTypeSlice(bytes)if err != nil {fmt.Println("Error:", err)return}fmt.Println("[]myType-->", myTypes)}func ByteSliceToMyTypeSlice(data []byte) ([]MyType, error) {buf := bytes.NewReader(data) // 将输入的字节切片data包装成一个只读的缓冲区buf。可以方便地按顺序读取字节,无需关心底层的字节切片操作。fmt.Println("buf-->", buf)var result []MyTypefor buf.Len() > 0 {var value MyType // value表示 []MyType 的元素if err := binary.Read(buf, binary.LittleEndian, &value); err != nil {// 从缓冲区buf中 以小段字节序LittleEndian的形式 读取数据到value中return nil, err}result = append(result, value) // 将value添加进 []MyType 中}return result, nil
}

如何实现字符串和byte切片的零拷贝转换?

package mainimport "fmt"func main() {str := "123"fmt.Println([]byte(str))
}

go中string和[]byte需要互相转化时使用string(byte[])和[]byte(str),这种情况会扩展新的内存空间来存储,是深拷贝。

零拷贝使用unsafe实现。

package mainimport ("fmt""unsafe"
)func main() {str := "Hello, World!"// unsafe.Pointer(&str):将字符串地址转为通用指针类型。// 将 unsafe.Pointer 转换为 []byte 的指针,并解引用为实际的 []byte 值。b := *(*[]byte)(unsafe.Pointer(&str))fmt.Println(b, string(b)) // [72 101 108 108 111 44 32 87 111 114 108 100 33] Hello, World!
}

Go1.22版本编译器对字符串和[]byte之间的转换进行了优化,在某些特定场景下实现了零拷贝。然而,这种优化主要依赖于编译器的内联和逃逸分析,只有在未发生逃逸的情况下才能生效。因此,并非所有场景下都能实现零拷贝转换


http://www.mrgr.cn/news/89917.html

相关文章:

  • MySQL开窗函数种类和使用总结
  • 开发一款类似《王者荣耀》的游戏是一个复杂的系统工程,涉及多个领域的知识和技术。以下是从多个角度详细阐述如何开发的思维。
  • 想品客老师的第十二天:异步和promise
  • 【PDF多区域识别】如何批量PDF指定多个区域识别改名,基于Windows自带的UWP的文字识别实现方案
  • 排序算法与查找算法
  • 2024第十五届蓝桥杯网安赛道省赛题目--cc(CyberChef)/crypto
  • jakarta EE学习笔记-个人笔记
  • python:如何播放 .spx 声音文件
  • Unity扩展编辑器使用整理(一)
  • python 语音识别方案对比
  • AI大模型零基础学习(1):大模型使用篇
  • JavaScript 复习
  • Linux ftrace 内核跟踪入门
  • 【算法】动态规划专题⑦ —— 多重背包问题 + 二进制分解优化 python
  • #渗透测试#批量漏洞挖掘#微商城系统 goods SQL注入漏洞
  • C++ Primer 成员访问运算符
  • 快速在wsl上部署学习使用c++轻量化服务器-学习笔记
  • 【自开发工具介绍】SQLSERVER的ImpDp和ExpDp工具演示04
  • 私有化部署DeepSeek并SpringBoot集成使用(附UI界面使用教程-支持语音、图片)
  • C++ Primer 递增和递减运算符
  • 120,【4】 攻防世界 web Confusion1(jinja2)
  • 介绍10个比较优秀好用的Qt相关的开源库
  • 音频进阶学习十二——Z变换一(Z变换、收敛域、性质与定理)
  • [论文阅读] Knowledge Fusion of Large Language Models
  • 图解BWT(Burrows-Wheeler Transform) 算法
  • DeepSeek与人工智能的结合:探索搜索技术的未来