Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 修改列表元素中的固定大小数组_Arrays_List_Go_Interface_Micro Optimization - Fatal编程技术网

Arrays 修改列表元素中的固定大小数组

Arrays 修改列表元素中的固定大小数组,arrays,list,go,interface,micro-optimization,Arrays,List,Go,Interface,Micro Optimization,我正在使用的Golang对我的LRU缓存解决方案进行微优化。我的解决方案是使用一个map[int]*list.Element,其中每个list.listlist.Element是[]int,其中[0]是键,[1]是值 我试图从[]int移动到[2]int进行优化,但是我遇到了这样一个问题:在ee:=e.Value之后修改固定大小数组([2]int)(注意固定大小数组的[2]int类型)不再修改列表中的基础值,与w/ee:=e.Value.([]int)(请注意[]int类型)的情况不同,我想这是

我正在使用的Golang对我的LRU缓存解决方案进行微优化。我的解决方案是使用一个
map[int]*list.Element
,其中每个
list.list
list.Element
[]int
,其中
[0]
是键,
[1]
是值

我试图从
[]int
移动到
[2]int
进行优化,但是我遇到了这样一个问题:在
ee:=e.Value之后修改固定大小数组([2]int)
(注意固定大小数组的
[2]int
类型)不再修改
列表中的基础值,与w/
ee:=e.Value.([]int)
(请注意
[]int
类型)的情况不同,我想这是非常合理的,因为切片基于引用,而固定大小的数组基于复制的值

我尝试过像
e.Value。([2]int)[1]=…
,以及与
:=&e.Value…
的各种组合,以及从
[2]int
转换到
[]int
,但这都会导致编译器错误

问:是否无法将
容器/列表
与嵌入式数组一起使用,并对所述固定大小数组进行适当修改?

如您所述:

我想这很有道理,因为切片基于引用,而固定大小的数组基于复制的值

因此,如果您想实现这一点,您需要通过存储指向数组的指针来使用对固定大小数组的引用,而不是数组值

这样,您就可以通过list元素修改底层数组

请参见此处的简单示例:

package main

import (
    "container/list"
    "fmt"
)

func main() {

    l := list.New()

    // create a fixed size array and initialize it
    var arr [2]int
    arr[0] = 1
    arr[1] = 2
    // push a pointer to the array into the list
    elem := l.PushFront(&arr)
    // modify the stored array
    elem.Value.(*[2]int)[0] = 3
    // print the element from iterating the list
    for e := l.Front(); e != nil; e = e.Next() {
        fmt.Println(e.Value)
    }
    // print the underlying array, both are modified
    fmt.Println(arr)

}
编辑

请注意,这种行为不是此列表实现特有的,而是与类型断言在语言本身中的工作方式有关

请看这里:

引用该节的内容(并加上我自己的重点):

该语法借用了打开类型开关的子句,但使用了显式类型而不是类型关键字:
value.(typeName)
结果是一个新值,该值带有静态类型typeName

使用引用类型时,复制值不会影响您,因为复制指针值最终允许您更改相同的基础引用

但是,当数组本身是一个值时,将其指定给副本是没有意义的。当您试图直接修改数组时(不将类型断言分配给变量),Go甚至会在编译时捕捉到这一点,这样您就不会分配给这个“临时”副本,这显然是一个错误。这就是您在尝试执行此操作时出现所有语法错误的原因

要克服这一点(如果您不想使用指针),一种可能是您可以实现自己的
列表
,借用您正在使用的实现,但将
元素
的值设置为显式的
[2]int
,而不是接口


这将消除进行类型断言的需要,并且您将能够修改底层数组。

还尝试了
[:]
技巧-返回
第38行:无效操作e.Value。([2]int)[:](无法寻址的值片段)
请注意,一旦使用
*[2]int
使用指针结构没有好处:
*struct{key,value int}
,该结构将使代码更清晰。这里的问题是效率。我猜指向数组的指针会比片稍快一些,但至少在概念上,它听起来确实比list.Element中的嵌入式数组慢一些,特别是因为涉及到额外的垃圾收集,imho。这个答案是否表明确实没有办法修改list.Element本身中的嵌入数组?这似乎是一个相当武断的限制,我想不出任何好的理由。@cnst:我编辑了我的答案,以进一步说明为什么它在使用非引用值时不起作用。@eugenioy,哦,我明白了-创建副本的断言,现在至少开始理解为什么解引用组合不起作用了。现在唯一剩下的部分是,是否有一种方法可以在不使用断言的情况下访问这些内容,或者以任何其他方式修改值(当然,除了制作自己的列表实现之外)?否则,这似乎仍然是一个主要的性能限制,背后没有任何好的理由。@cnst,因为它存储为“接口{}”,所以除了通过类型断言之外,没有办法将其视为数组。您可以研究反射和/或使用“不安全”包上的功能,但所有这些都可能比只实现自己的列表更复杂(甚至效率更低)。