在Go中分配切片与重新定义切片
我试图使用切片作为队列数据结构,我提出了这个实现,它产生了一个无限循环。这是因为在Go中分配切片与重新定义切片,go,slice,assign,declare,Go,Slice,Assign,Declare,我试图使用切片作为队列数据结构,我提出了这个实现,它产生了一个无限循环。这是因为queueslice不会使用子切片queue[1://code>进行更新 func badQueue() { queue := []int{0,1,2,3,4,5} for len(queue) > 0 { current, queue := queue[0], queue[1:] fmt.Println(current, queue) } } 我发现问
queue
slice不会使用子切片queue[1://code>进行更新
func badQueue() {
queue := []int{0,1,2,3,4,5}
for len(queue) > 0 {
current, queue := queue[0], queue[1:]
fmt.Println(current, queue)
}
}
我发现问题与我重新声明当前
和队列
(使用:=
)而不是分配值有关,这解决了问题:
func goodQueue() {
queue := []int{0,1,2,3,4,5}
var current int
for len(queue) > 0 {
current, queue = queue[0], queue[1:]
fmt.Println(current, queue)
}
}
我知道是什么导致了这个问题,但我不完全理解为什么在这种情况下,重新声明操作的工作方式与赋值不同。为什么不使用队列的子片(queue[1://code>)重新声明队列
谢谢 在短声明情况下,变量queue
的作用域仅限于循环体,即为每个新迭代销毁和创建。引述
与常规变量声明不同,短变量声明可以重新声明具有相同类型的同一块(如果块是函数体,则为参数列表)中最初声明的变量,并且至少有一个非空变量是新的。因此,重新声明只能出现在多变量短声明中。重新声明不会引入新变量;它只是将一个新值赋给原始值
因为可以有多个同名变量,只要它们的作用域不同。内部作用域中的变量将在外部作用域中隐藏变量
所以如果我们分解你的例子
func badQueue() {
// queue from outer scope, lets call it A
queue := []int{0,1,2,3,4,5}
// the only visible queue here is A, so len(queue) will always refer to A
for len(queue) > 0 {
// same thing here, the only visible queue is A, so queue[0] and queue[1:]
// both refer to A
// We are also declaring new variables, queue and current
// This queue is now shadowing the outer queue, let's call this one B
current, queue := queue[0], queue[1:]
// Here queue will refer to B
fmt.Println(current, queue)
// When the current iteration of the loop ends current and queue B is destroyed
// because they go out of scope and the loop start over with A unchanged
}
}
要了解这在Go中的工作原理,需要两点:
范围
Go使用时,每个括号对将创建一个新的范围,如果内部范围中的标识符具有相同的声明名称,则它们将与外部范围中的标识符形成阴影
func main() {
var name string = "Golang"
fmt.Printf("Outer Scope: %s\n", name) // Print "Golang"
{
var name string = "Java"
fmt.Printf("Inner Scope: %s\n", name) // Print "Java"
}
fmt.Printf("Outer Scope: %s\n", name) // Print "Golang" again
}
运算符:=
是一个复合操作,它将在一个语句中执行多项操作:声明、类型推断和赋值,基本上您可以将其视为语法糖。S1和S2的以下代码示例是等效的:
func main() {
// S1
var name string = "Golang"
// S2
name := "Golang"
}
考虑到以上两点,翻译后您的代码将如下所示:
func badQueue() {
queue := []int{0,1,2,3,4,5}
for len(queue) > 0 {
var current int
var queue []int
current, queue = queue[0], queue[1:]
fmt.Println(current, queue)
}
}
可以清楚地看到,外部队列
在for
循环内部不受影响
顺便说一句,对于:=
左侧的每个变量,编译器将查找当前块范围以尝试解析标识符,如果之前已经声明了标识符,编译器将重用它,而不是创建新的标识符。但是,如果之前声明了所有lhs变量,编译器将报告一个错误,并显示消息“在:=”的左侧没有新变量”。请查看以下代码:
func main() {
var name string
name, age := "Golang", 10 // reuse the above 'name' and create a new variable 'age'
var tom, jerry string
tom, jerry := "Tom", "Jerry" // no new variables on left side of :=
}
这里是为那些对细节感兴趣的人准备的。“我不完全理解为什么在这种情况下,重新声明操作的工作方式与分配不同。”--因为Go是。谢谢,现在它非常有意义!
func badQueue() {
queue := []int{0,1,2,3,4,5}
for len(queue) > 0 {
var current int
var queue []int
current, queue = queue[0], queue[1:]
fmt.Println(current, queue)
}
}
func main() {
var name string
name, age := "Golang", 10 // reuse the above 'name' and create a new variable 'age'
var tom, jerry string
tom, jerry := "Tom", "Jerry" // no new variables on left side of :=
}