当前位置: 首页 > 面试题库 >

为什么切片值有时会过时但不能映射值?

宗政文彬
2023-03-14
问题内容

我发现切片图功能和通道经常一起作为 参考类型 提及。但是我注意到,切片的东西不会表现出参考行为,就像它们会过时一样:

   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)

通常,我会通过牢记切片描述符实现的内部组件来理解这一点:切片值可以视为len,cap和data指针的结构。

但是地图值永远不需要像

   m := make(map[string]int)
   ...
   // don't know how to express with insertion, but you know what i mean.
   m = delete(m, "well")

为什么?映射值仅仅是指向映射描述符的指针吗?如果是这样,为什么还不这样做呢?


问题答案:

在Go中,没有像C ++中那样的引用类型。在Go中,一切都是通过价值传递的。当在Go中使用术语“引用类型”时,它表示引用它们应表示的数据的类型(通过指针)。

切片是小型的,类似于结构的数据结构,由类型表示reflect.SliceHeader

type SliceHeader struct {
        Data uintptr
        Len  int
        Cap  int
}

它包含一个指向基础数组(SliceHeader.Data字段)中切片的第一个元素的指针。该结构很小,可以作为值有效传递,而无需传递其地址(并取消引用以间接访问其任何字段)。切片的元素不存储在切片头中,而是存储在头的存储区域之外的数组中。这意味着修改“指向”元素将修改原始切片的元素。

当您将(大于0)个元素追加到切片时,Len标头中的字段必须更改,因此描述带有其他元素的切片的新切片必须不同于追加之前的切片,这就是为什么您需要分配内置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
}

如您所见,这是一个比切片头复杂得多的数据结构,并且要大得多,将其作为值传递将是无效的。

从映射添加/删除元素(键-值对)存储在此结构的字段所引用的存储桶中,但是由于映射在后台作为指针处理,因此您无需分配此类操作的结果。

为了完整起见,通道也被实现为指针,指向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描述器实现的内部组件来理解这一点的:slice值可以被看作len、cap和数据指针的结构。 但是地图值永远不需要像 为什么?映射值只是映射描述符的指针吗?如果是这样,为什么不这样做呢?

  • 问题内容: 在非官方指南中有一个占位符答案,带有指向(对我而言)似乎无关的文章的链接。 我使用XJC生成我的JAXB类,尽管它们大多数按预期相互映射,但有些元素被映射到。这对于带有循环的图最令人讨厌,其中有时Foo元素的父节点将是,而它本身没有父属性,从而中断了循环。 我可以想到各种解决方法,但是如果有人可以向我解释这种行为,那就更好了。为什么JAXB有时将元素映射到而不是Foo? 问题答案: 在

  • 我只想用hadoop mapreduce来排序我的日志行。我将该行的所有字段作为输出键,并将输出值设置为null。但是当运行时,在第行出现空指针异常 所以为什么hadoop映射的输出值不能为空?为什么hadoop reduce的输出值可以(我测试过)?

  • 问题内容: 在玩Go代码时,我发现映射值不可寻址。例如, 产生错误 mapaddressable.go:7:无法获取mymap [1]的地址 而代码, 工作完美。 为什么会这样呢?为什么Go开发人员选择使某些值无法解决?这是语言的缺点还是功能? 编辑 :来自C ++背景,我不习惯于这种流行趋势。例如,以下代码可以正常工作: 如果有人可以指出为什么在Go中无法实现(或故意没有实现)相同的 寻址 能力

  • 多值映射不存在的原因是什么?会不会是什么过滤?对于未知数量的参数,有什么可供选择的? 更新是由于泽西+Spring的一个特殊性。在这个答案中可以找到解决方法。

  • 我想通过数组映射,但我得到一个错误:TypeError: locationAddress.map不是一个函数 我是新来的反应和反应钩。我一直试图简化数组,但运气不好。知道为什么这不起作用吗? 编辑:到目前为止,我尝试了答案中的所有更改,但错误仍然存在。我包括了更多的代码和包。json文件。我尝试停用一些函数,如useEffect,现在只有在我尝试键入要映射的输入字段时才会显示错误。 找到解决方案: