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

Java转Go日记(一):Slice解密

1.切片通过函数,传的是什么?

package mainimport ("fmt""reflect""unsafe"
)func main() {s := make([]int, 5, 10)PrintSliceStruct(&s)test(s)
}func test(s []int) {PrintSliceStruct(&s)
}func PrintSliceStruct(s *[]int) {ss := (*reflect.SliceHeader)(unsafe.Pointer(s))fmt.Println("slice struct: %+v, slice is %v\n", ss, s)
}

切片是引用类型

  • 切片在函数间传递时,SliceHeader(slice 的内部结构) 会被复制,Data 指针指向的底层数组是共享的。因此,修改切片元素会影响所有引用该底层数组的切片。

2.在函数里面改变切片,函数外的切片会被影响吗?

package mainimport ("fmt""reflect""unsafe"
)func main() {s := make([]int, 5, 10)case1(s)case2(s)PrintSliceStruct(&s)
}func PrintSliceStruct(s *[]int) {ss := (*reflect.SliceHeader)(unsafe.Pointer(s))fmt.Println("slice struct: %+v, slice is %v\n", ss, s)
}// 底层数组变化
func case2(s []int) {s = append(s, 0)s[1] = 1PrintSliceStruct(&s)
}// 底层数组不变
func case1(s []int) {s[1] = 1PrintSliceStruct(&s)
}

总结:

操作是否影响外部切片说明
s[i] = x✅ 是直接修改底层数组
append(未扩容)⚠️ 部分影响(len 不变)修改元素会影响,但 len 不会变
append(扩容)❌ 否新切片指向新数组
传递 *[]int✅ 是直接修改外部切片

3.截取切片

通过操作得到的新slice和原slice是什么关系?

(1) 底层数组共享

  • 新切片和原切片指向同一个底层数组,修改其中一个的元素会影响另一个。

(2) 新切片的长度和容量变化

  • 新切片的 len 取决于截取的范围(s[low:high]len = high - low)。

  • 新切片的 cap 是原切片 cap - low(即从 low 开始到原底层数组末尾)。

(3) append 是否触发扩容

  • 如果新切片 append未超过底层数组容量,修改会影响原切片。

  • 如果 append超过容量,Go 会分配新数组,此时新切片与原切片不再共享底层数组。

package mainimport ("fmt""reflect""unsafe"
)func main() {s := make([]int, 5, 10)case1(s)case2(s)case3(s)case4(s)PrintSliceStruct(&s)
}func PrintSliceStruct(s *[]int) {ss := (*reflect.SliceHeader)(unsafe.Pointer(s))fmt.Println("slice struct: %+v, slice is %v\n", ss, s)
}// 截取获得新切片
func case4(s []int) {s1 := s[2:]PrintSliceStruct(&s1)
}// 截取[len(s) - 1, ]区间元素
func case3(s []int) {s = s[len(s)-1:]PrintSliceStruct(&s)
}// 截取[1,2]区间元素
func case2(s []int) {s = s[1:3]PrintSliceStruct(&s)
}// 截取0号以后的元素
func case1(s []int) {s = s[1:]PrintSliceStruct(&s)
}

output:

slice struct: %+v, slice is %v&{1374390288392 4 9} &[0 0 0 0]
slice struct: %+v, slice is %v&{1374390288392 2 9} &[0 0]
slice struct: %+v, slice is %v&{1374390288416 1 6} &[0]
slice struct: %+v, slice is %v&{1374390288400 3 8} &[0 0 0]
slice struct: %+v, slice is %v&{1374390288384 5 10} &[0 0 0 0 0]

4.删除元素:

package mainimport ("fmt""reflect""unsafe"
)func main() {s := []int{0, 1, 2, 3, 4}_ = s[4]PrintSliceStruct(&s)s1 := append(s[:1], s[2:]...)PrintSliceStruct(&s1)PrintSliceStruct(&s)// 访问原切片_ = s[4]// 访问原切片中删除了一个元素的切片_ = s1[4]
}func PrintSliceStruct(s *[]int) {ss := (*reflect.SliceHeader)(unsafe.Pointer(s))fmt.Println("slice struct: %+v, slice is %v\n", ss, s)
}

output:

slice struct: %+v, slice is %v&{1374389641552 5 5} &[0 1 2 3 4]
slice struct: %+v, slice is %v&{1374389641552 4 5} &[0 2 3 4]
slice struct: %+v, slice is %v&{1374389641552 5 5} &[0 2 3 4 4]
panic: runtime error: index out of range [4] with length 4goroutine 1 [running]:
main.main()/Users/admin/GolandProjects/Go_study/slice/slice_4/main/slice_4.go:23 +0x1a8
  • 关键发现:s 的内容也被修改了!

  • 因为 ss1 共享底层数组,append操作修改了数组内容

最后一个4是原数组的残留值

5.添加元素

package mainimport ("fmt""reflect""unsafe"
)func main() {case1()case2()case3()}func case3() {s1 := make([]int, 3, 3)s2 := append(s1, 1)PrintSliceStruct(&s1)PrintSliceStruct(&s2)
}func case2() {s1 := make([]int, 3, 4)s2 := append(s1, 1)PrintSliceStruct(&s1)PrintSliceStruct(&s2)
}func case1() {s1 := make([]int, 3, 3)s1 = append(s1, 1)PrintSliceStruct(&s1)
}func PrintSliceStruct(s *[]int) {ss := (*reflect.SliceHeader)(unsafe.Pointer(s))fmt.Println("slice struct: %+v, slice is %v\n", ss, s)
}

Output:

slice struct: %+v, slice is %v&{1374390272048 4 6} &[0 0 0 1]
slice struct: %+v, slice is %v&{1374390296608 3 4} &[0 0 0]
slice struct: %+v, slice is %v&{1374390296608 4 4} &[0 0 0 1]
slice struct: %+v, slice is %v&{1374390231160 3 3} &[0 0 0]
slice struct: %+v, slice is %v&{1374390272096 4 6} &[0 0 0 1]

6.slice深度拷贝的方法

相关文章:

  • 【字符串的hashCode】hashCode相等但是对应的字符串值不一定相等
  • 分类别中位数归一化
  • 常用正则化技术dropout
  • spark-SQL数据加载和保存
  • Redis清空缓存
  • 【解析】ReentrantLock锁、Syschronized锁面试点解析
  • 数启新疆,智领未来!2025新疆数字经济发展战略研讨会在乌市启幕
  • go学习记录(第二天)
  • unityTEngine 框架学习记录1
  • OpenCv高阶(四)——角点检测
  • 充电宝项目中的MQTT(轻量高效的物联网通信协议)
  • Sherpa简介
  • 公务员体检肌酐临界值处理指南
  • 比特率、码元速率(波特率)的定义、关系及相关计算公式
  • 代码随想录算法训练营day5(哈希表)
  • 【Python进阶】字典:高效键值存储的十大核心应用
  • Web开发-JavaEE应用原生和FastJson反序列化URLDNS链JDBC链Gadget手搓
  • 构件技术(高软58)
  • 永磁同步电机控制中,滑模观测器是基于反电动势观测转子速度和角度的?扩展卡尔曼滤波观测器是基于什么观测的?扩展卡尔曼滤波观测器也是基于反电动势吗?
  • 高防CDN、高防IP vs 高防服务器:核心优势与选型指南
  • 奶茶加盟网站建设公司哪家好/seo门户网站优化
  • ip查询网站备案查询系统/做一个网站
  • 网站经营内容/app推广是什么意思
  • 记事本做网站怎么改字体颜色/百度seo 优化
  • 做网站必须注册的商标/西安seo关键词查询
  • 基层消防力量建设/seo优化关键词是什么意思