英文:
Why there are two ways of declaring variables in Go, what's the difference and which to use?
问题
根据Go参考文档,声明变量有两种方式:
变量声明(格式为var count = 0
或var count int
)
和
短变量声明(格式为count := 0
)
我发现很难决定使用哪种方式。
我目前了解到的区别有:
- 只能在函数作用域内使用
count := 0
格式。 count := 0
可以在多变量短声明中进行重新声明。
但据我所知,它们的行为是相同的。在参考文档中也提到:
> 它(count := 0
的方式)是使用初始化表达式但没有类型的常规变量声明的简写形式
我的困惑是:
-
如果其中一种只是另一种的简写方式,为什么它们的行为不同?
-
在Go的作者看来,为什么要有两种声明变量的方式(为什么它们没有合并成一种方式)?只是为了让我们困惑吗?
-
在使用它们时,还有其他方面需要注意的吗,以防我掉进陷阱?
英文:
According to the Go reference there are two ways of declaring a variable
Variable_declarations (in the format of var count = 0
or var count int
)
and
Short_variable_declarations (in the format of count := 0
)
I found it's very confusing to decide which one to use.
The differences I know (till now) are that:
- I can only using a
count := 0
format when in the scope of a function. count := 0
can be redeclared in a multi-variable short declaration.
But they do behave the same as far as I know. And in the reference it also says:
> It (the count:=0
way) is shorthand for a regular variable declaration with initializer expressions but no types
My confusions are:
- If one is just the shorthand way of the other, why do they behave differently?
- In what concern does the author of Go make two ways of declaring a variable (why are they not merged into one way)? Just to confuse us?
- Is there any other aspect that I should keep my eyes open on when using them, in case I fall into a pit?
答案1
得分: 70
变量声明清楚地表明了变量的声明。var
关键字是必需的,它很短并且表达了正在进行的操作(在文件级别上,除了注释之外的所有内容都必须以关键字开头,例如package
、import
、const
、type
、var
、func
)。与任何其他块一样,变量声明可以像这样分组:
var (
count int
sum float64
)
你不能用短变量声明来做到这一点。此外,你可以在变量声明中不指定初始值,这种情况下每个变量将具有其类型的零值。短变量声明不允许这样做,你必须指定初始值。
Go语言的一个设计原则是使语法简洁。许多语句要求或者允许在语句体中声明仅在该语句体中可用的局部变量,例如for
、if
、switch
等。为了使语法更清晰、更简短,短变量声明在这些情况下是合理的,并且它们的作用是明确的。
for idx, value := range array {
// 使用索引和值做一些操作
}
if num := runtime.NumCPU(); num > 1 {
fmt.Println("多核CPU,核心数:", num)
}
另一个区别:重声明
引用自语言规范:
与常规变量声明不同,短变量声明可以重新声明变量,前提是它们在同一块中以相同的类型进行了原始声明,并且至少有一个非空白变量是新的。因此,重声明只能出现在多变量的短声明中。重声明不会引入新变量;它只是给原始变量赋予新值。
这也很方便。假设你想进行正确的错误处理,你可以重用一个err
变量,因为很可能你只需要检查上次函数调用是否有任何错误:
var name = "myfile.txt"
fi, err := os.Stat(name) // fi和err都是首次声明
if err != nil {
log.Fatal(err)
}
fmt.Println(name, fi.Size(), "字节")
data, err := ioutil.ReadFile(name) // data是新的,但err已经存在
// 所以只是给err赋予了新值
if err != nil {
log.Fatal(err)
}
// 对data做一些操作
英文:
The Variable declarations make it clear that variables are declared. The var
keyword is required, it is short and expresses what is done (at the file level everything excluding comments has to start with a keyword, e.g. package
, import
, const
, type
, var
, func
). Like any other block, variable declarations can be grouped like this:
var (
count int
sum float64
)
You can't do that with Short variable declarations. Also you can use Variable declarations without specifying the initial value in which case each variable will have the zero value of its type. The Short variable declaration does not allow this, you have to specify the initial value.
One of Go's guiding design principle was to make the syntax clean. Many statements require or it is handy that they allow declaring local variables which will be only available in the body of the statement such as for
, if
, switch
etc. To make the syntax cleaner and shorter, Short variable declaration is justified in these cases and it is unambigous what they do.
for idx, value := range array {
// Do something with index and value
}
if num := runtime.NumCPU(); num > 1 {
fmt.Println("Multicore CPU, cores:", num)
}
Another difference: Redeclaration
Quoting from the Language specification:
> Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block with the same type, and at least one of the non-blank variables is new. As a consequence, redeclaration can only appear in a multi-variable short declaration. Redeclaration does not introduce a new variable; it just assigns a new value to the original.
This one is also handy. Suppose you want to do proper error handling, you can reuse an err
variable because most likely you only need it to check if there were any errors during the last function call:
var name = "myfile.txt"
fi, err := os.Stat(name) // fi and err both first declared
if err != nil {
log.Fatal(err)
}
fmt.Println(name, fi.Size(), "bytes")
data, err := ioutil.ReadFile(name) // data is new but err already exists
// so just a new value is assigned to err
if err != nil {
log.Fatal(err)
}
// Do something with data
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论