- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我发现 slice 映射函数和 channel 经常作为引用类型一起提到。但是我注意到 slice 的东西没有表现出引用行为,就像它们可能会过时一样:
var s []int
//must update slice value
s = append(s, ...)
或
//must use pointer if we want to expose the change
func foo(s *[]int) error
//or change the function signature to return it like _append_
func foo(s []int) (r slice, err error)
通常我通过牢记 slice 描述符实现的内部组件来理解这一点: slice 值可以看作是 len、cap 和数据指针的结构。
但是 map 值永远不需要像这样打扰
m := make(map[string]int)
...
// don't know how to express with insertion, but you know what i mean.
m = delete(m, "well")
为什么? map 值只是指向 map 描述符的指针吗?如果是这样,为什么不也用这种方式制作 slice 呢?
最佳答案
在 Go 中没有像 C++ 中那样的引用类型。在 Go 中,一切都是按值传递的。当术语“引用类型”在 Go 中使用时,它表示引用它们应该表示的数据的类型(通过指针)。
slice 是小型的、类似结构的数据结构,由 reflect.SliceHeader
类型表示:
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
它包含指向底层数组(SliceHeader.Data
字段)中 slice 第一个元素的指针。这个结构体很小,作为值传递很有效,不需要传递它的地址(并取消引用它以间接访问它的任何字段)。 slice 的元素不存储在 slice 头中,而是存储在头内存区域之外的数组中。这意味着修改“尖头”元素将修改原始 slice 的元素。
当您将(超过 0 个)元素附加到 slice 时, header 中的 Len
字段必须更改,因此描述具有附加元素的 slice 的新 slice 必须不同于追加之前的一个,这就是为什么您需要分配内置 append()
函数的返回值。 (其他值也可能会改变,但 Len
肯定会改变。)
映射被实现为指向 runtime.hmap
结构的指针:
type hmap struct {
// Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.
// Make sure this stays in sync with the compiler's definition.
count int // # live cells == size of map. Must be first (used by len() builtin)
flags uint8
B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
hash0 uint32 // hash seed
buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
extra *mapextra // optional fields
}
如您所见,这是比 slice header 复杂得多的数据结构,而且要大得多,将其作为值传递效率不高。
从映射中添加/删除元素(键值对)存储在该结构的字段引用的桶中,但由于映射在引擎盖下作为指针处理,因此您不需要分配结果这样的操作。
为了完整起见, channel 也被实现为指针,指向runtime
包的hchan
类型:
type hchan struct {
qcount uint // total data in the queue
dataqsiz uint // size of the circular queue
buf unsafe.Pointer // points to an array of dataqsiz elements
elemsize uint16
closed uint32
elemtype *_type // element type
sendx uint // send index
recvx uint // receive index
recvq waitq // list of recv waiters
sendq waitq // list of send waiters
// lock protects all fields in hchan, as well as several
// fields in sudogs blocked on this channel.
//
// Do not change another G's status while holding this lock
// (in particular, do not ready a G), as this can deadlock
// with stack shrinking.
lock mutex
}
这又是一个“胖”结构,处理方式与映射值类似。
查看相关问题:
slice vs map to be used in parameter
Appending to a slice with enough capacity using value receiver
Are golang slices pass by value?
What do "value semantics’" and "pointer semantics" mean in Go?
关于dictionary - 为什么 slice 值有时会过时但永远不会映射值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55520624/
试图自学,但发现很难找到示例,我的大脑已经陷入了困境。非常不确定 3 和 4,需要帮助才能使 5 正常工作。 package main import "fmt" func main () {
我有一个 slice ,它由字符串类型的 slice 组成。我希望能够为这片 slice 的各个元素赋值,不一定按顺序。然后,稍后,我希望能够更改任何特定元素的值。我已经阅读了有关 slice 的相同
我正在尝试将整数 slice append 到由整数 slice 组成的 slice 。当我打印 slice 时,它按预期显示。但是,当我将 slice append 到一片 slice 时,内容会发
我读了go slice usage and internals和 Slice和 Effective go#slice但是没有像这样用 3 个数字 slice 的方法:slice[a:b:c] 例如这段
这个问题在这里已经有了答案: Are slices passed by value? (5 个答案) 关闭 8 个月前。 如果可能的话,我正在努力使我的代码更具性能以节省内存 我做了一些研究,但找不
我是 Golang 的新手。 当我尝试它时,出现编译错误: cannot use a.B (type []*C) as type []Z in field value 代码: package main
我有数据结构: type PosList []int type InvertedIndex struct { Capacity int Len int IndexList [
我在 Go 中使用矩阵乘法进行一些性能实验并遇到了一些意想不到的结果。 版本 1: func newMatrix(n int) [][]int { m := make([][]int, n)
文档涵盖了 slice() 的 3 种用法对象: obj[:stop] = obj[slice(stop)] obj[start:stop] = obj[slice(start, stop)] obj
我有以下表示网页的结构 type Webpage struct { url.URL references []url.URL } 我想将网站表示为网页的集合。我正在使用这个结构,但感觉
我有一个这样的结构: type Headers struct { header string valueFromCalculation string
我正在参观 Golang 网站,我正在尝试消化其中一个示例。目前还不清楚它是如何工作的: package main import "fmt" func main() { s := []int{
我很好奇解包 slice 并将它们作为参数发送给可变参数函数。 假设我们有一个带有可变参数的函数: func unpack(args ...interface{}) 如果我们不想传入它工作的接口(in
我正在尝试解码来自服务器的 gzip 响应,该响应是一个 msgpack 数组或最终被 gzip 压缩的 msgpack 数组。 为了说明这一点,我的回复看起来像这样: gzip(msgpack([m
我是 Go 编程的新手。我在 Go 编程书籍中读到 slice 由三部分组成:指向数组的指针、长度和容量。 我很困惑: nil slice ( slice 没有可指向的底层数组,len = 0,cap
在Go Programming Language书中,作者给出了append()函数的以下代码示例,该函数接受[]int和int作为参数,并将相应地处理调整大小: // gopl.io/ch4/app
我在代码高尔夫游戏中尝试优化字符串复数时遇到了这个怪癖。我的想法是将字符串写成复数形式,然后使用 substr 有条件地切断最后一个字符: var counter = 1; var myText =
我有一个字符串数组:slice1 [][]string。我使用 for 循环获得了我想要的值: for _, i := range slice1 { //[string1 string2] f
我正在尝试实现一个将 TCP 端口 slice 拆分为 x 个其他 slice 的功能。这些 slice 将发送给将扫描这些端口的工作人员,因此 x 由工作人员的数量设置。 这是代码: // crea
我有以下代码 func Sum(a []int) int { res := 0 for _, n := range a { res += n } ret
我是一名优秀的程序员,十分优秀!