我正在Golang对我的LRU缓存解决方案进行微优化,我正在使用https://golang.org/pkg/container/list/.我的解决方案通过具有一个map[int]*list.Element
来工作,其中每个list.List
list.Element
都是[]int
,[0]
是密钥,[1]
是值。
我正试图从[]int
移动到[2]int
进行优化,但后来我遇到了一个问题,即在ee := e.Value.([2]int)
(注意固定大小数组的[2]int
类型(之后修改固定大小数组不再修改list.Element
中的基本值,这与w/ee := e.Value.([]int)
(注意[]int
类型(的情况不同,我想这是完全合理的,因为切片是基于引用的,而固定大小的数组是基于复制的值。
我尝试过e.Value.([2]int)[1] = …
之类的东西,以及与:= &e.Value…
的各种组合,以及从[2]int
到[]int
的转换,但都会导致编译器错误。
Q:是否无法将container/list
与嵌入式阵列一起使用,并对所述固定大小的阵列进行适当的修改
如您所述:
我想这很有道理,因为切片是基于引用的,而固定大小的数组是基于复制的值
因此,如果您想实现这一点,您需要通过存储指向数组的指针而不是数组值来使用对固定大小数组的引用。
这样,您就可以通过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)
}
编辑
请注意,这种行为并不是这个列表实现特有的,而是与类型断言在语言本身中的工作方式有关。
请参阅此处:
https://golang.org/doc/effective_go.html#interface_conversions
引用该部分(并添加我自己的重点(:
语法借用了打开类型开关的子句,但使用了显式类型而不是类型关键字:
value.(typeName)
和,结果是静态类型为typeName的新值。
使用引用类型时,复制值不会影响您,因为复制指针值最终会允许您更改相同的基础引用。
但是,当数组本身是一个值时,分配给副本是没有意义的。当您尝试直接修改数组时(不将类型断言分配给变量(,Go甚至会在编译时捕捉到这一点,这样您就不会分配给这个"临时"副本,这显然是一个错误。这就是为什么你在尝试这样做时会出现所有语法错误。
为了克服这一点(如果您不想使用指针(,一种可能性是您可以实现自己的list
,借用您正在使用的实现,但使Element
的值成为显式[2]int
,而不是接口。
这将消除进行类型断言的需要,并且您将能够修改底层数组。