前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库Go 二维切片 共享 底层数组
GoGo语言与并发

Go 用 make 嵌套创建二维切片后,修改一行会影响其他行吗?

取决于内层切片是否各自独立分配。若多行复用同一个切片,修改任一行元素会同步影响其他行;逐行为每行分配独立底层数组则互不影响。

前端进阶之旅 · 一题精讲更新于 2026.09.05
Go#语言与并发#并发编程
先看核心答案
理解线索

切片共享的根源

  1. 内层分配每行用 make 分配独立数组,行间隔离。
  2. 同一引用多行赋同一元素,实际指向同一地址。
  3. 显式区分检查是否对每行单独 make 或 copy。

安全判断:需确认各行底层数组区间是否重叠,而不仅比较起始地址。

核心回答

先记住这个答案

用 make 双层创建切片时,make([][]int, n) 只分配外层,内层每个元素为 nil。必须再为每行分配独立切片,例如 m[i] = make([]int, col)。若让所有行指向同一个切片,则各行共享同一底层数组,修改一处全局生效。安全创建方式是逐行分配,或先建一维数组再划分成不相交的子切片,但后者需注意容量共享。

  • make 外层不自动分配内层切片。
  • 多行引用同一切片会互相影响。
  • 逐行分配是安全可靠的做法。

make 双层分配行为

make([][]int, n) 只创建一个长度为 n 的外层切片,其中每个元素都是内层切片类型的零值 nil,此时访问 m[0][0] 会 panic。要得到可用的矩阵,必须为每一行分配独立的底层数组,例如在循环中调用 m[i] = make([]int, col)。

另一种常见错误是先创建单一 row := make([]int, col),然后在循环里把同一 row 赋给多行。这样所有行的 slice header 都指向同一个底层数组,修改 m[0][j] 实际也修改了 m[1][j] 等。只有为每行分别调用 make 或复制数据,才能让行间真正独立。

传感器数据行污染事故

假设采集 5 个传感器各 3 个时刻的数据,代码写成 row := make([]int, 3),再用 row 为所有行赋值。后续某处执行 matrix[0][1] = 99 后,打印所有行会看到第 1 列全部变 99,因为 5 行共享同一片内存。原始观测被覆盖,日志失真。

修复方式为在循环内对每行执行 matrix[i] = make([]int, 3),确保每行有自己的数组。这样每次修改仅影响目标行。虽然增加了内存分配次数,但语义清晰且各阶段互不干扰。若需保留数据局部性,也可先分配一维 data := make([]int, 15),再让每行引用 data[i*3:(i+1)*3],此时行间不重叠,但容量管理需谨慎。

哪些情况会失效

失效条件:一旦某行被直接或间接赋值为另一个已存在的切片,且没有复制数据,就会产生共享。例如 m[0] = m[1] 后,修改 m[0][0] 会影响 m[1]。同样,从大切片切分出的子切片若互相重叠,也可能互相影响。

处理办法:若必须共享但又想隔离,用 copy 将数据复制到新分配的切片中。或者约束切片为非重叠的连续区间。代价是 copy 有 O(k) 时间开销;分享连续区间则少了内存拷贝,但需要自己维护索引与容量,且任一子切片扩容会分配新的底层数组并复制其自身元素,导致该子切片与其他子切片不再共享原数组,但原数组及其他子切片仍保持原地址。

回答前,多想一步

容易答错的地方

误以为 make 分配了内层
很多人以为 make([][]int, n, m) 可以同时指定外层长度和内层宽度,实际该写法中第二参数是外层长度、第三参数是外层容量,内层元素仍为 nil;必须先逐行 make 才能安全使用。
认为行默认一定独立
如果代码里把同一个切片变量放入多行,则行间共享。尤其从循环外构造一个 row 再循环赋值非常常见。检测办法:打印 &m[0][0] 和 &m[1][0],地址相同即共享。
试着用自己的话回答

面试官还会怎么问?

如何快速判断一个二维切片是否行间共享底层数组?

比较两行首个元素的地址:&m[0][0] == &m[1][0]。若为 true 则共享;也可以检查 cap 是否超过长度,但地址判断最直接。若首元素地址不同但可能后续重叠,需更复杂分析。

如果只读二维切片,是否不必关心是否共享?

只读场景不会写坏数据,但若误改则影响所有行,风险仍在。规范代码应在创建时就保证独立性,避免留下隐患,因为后续维护可能不经意修改。

有没有一次性分配所有内层内存又能保证行独立的写法?

可以用 data := make([]int, rows*cols) 再切分出不相交的子切片,每行指向 data[i*cols:(i+1)*cols]。这样行间不重叠,修改不影响他行,且内存连续分配效率高。但需注意子切片扩容会给整个大数组带来问题,通常适合不追加的场景。

从一道题,走向一组知识

把知识连起来

语言与并发

Go 对大切片取子切片后为什么会造成内存无法释放,如何避免?

同属「语言与并发」专题,接着看 Go 子切片 内存泄漏 底层数组 在具体场景中的处理方式。

语言与并发

Go 的 nil 切片和空切片有什么区别,序列化和判空时各要注意什么?

同属「语言与并发」专题,接着看 Go nil slice 空切片 区别 在具体场景中的处理方式。

参考资料

  • Effective Go

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. make 双层分配行为
  3. 传感器数据行污染事故
  4. 哪些情况会失效
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑