本专栏将从基础开始,循序渐进,由浅入深讲解Go语言,希望大家都能够从中有所收获,也请大家多多支持。
查看相关资料与知识库
专栏地址:Go专栏
如果文章知识点有错误的地方,请指正!大家一起学习,一起进步。
文章目录
变量声明
现在你已经对Go语言有了初步了解并完成了第一个练习,我们将深入探讨变量。我们的第一个重点是变量的声明。
变量用来暂时存储数据,以便你可以对其进行操作。当你声明一个变量时,你需要四个要素:声明变量的语句、变量的名称、变量能够存储的数据类型以及它的初始值。幸运的是,其中一些部分是可选的,这也意味着有多种方式来定义变量。
让我们详细了解所有声明变量的方法。
使用 var
声明变量
使用 var 是声明变量的基础方式。我们将要介绍的其他方法通常是这种方式的变体,通常通过省略一些部分来实现。一个完整的 var 声明如下:
var foo string = "bar"
其中关键部分包括 var、foo、string 和 = “bar”:
- var 表示我们正在定义一个变量。
- foo 是变量的名称。
- string 是变量的类型。
- = “bar” 是变量的初始值。
练习 1.02 – 使用 var
声明变量
在这个练习中,我们将使用完整的 var 语法声明两个变量,并将它们打印到控制台。你将看到 var 语法可以在代码的任何地方使用,这并不是所有变量声明语法都能做到的。开始吧:
创建一个新文件夹,并在其中添加一个名为 main.go 的文件。
在 main.go 文件的顶部添加 main 包名:
package main
添加所需的导入:
import ( "fmt" )
在包级作用域声明一个变量。我们将在后续详细讨论作用域:
var foo string = "bar"
创建 main() 函数:
func main() {
在函数内部使用 var 声明另一个变量:
var baz string = "qux"
将两个变量打印到控制台:
fmt.Println(foo, baz)
关闭 main() 函数:
}
保存文件。然后,在新文件夹中运行以下命令:
go run .
预期输出结果如下:
bar qux
在这个例子中,foo 在包级别声明,而 baz 在函数级别声明。变量声明的位置很重要,因为声明变量的位置也限制了你可以使用的声明语法。
接下来,我们将看另一种使用 var 语法的方式。
使用 var
一次声明多个变量
我们可以使用一个 var 声明来定义多个变量,这可以通过 var 块或语句来实现。这种方法在声明包级变量时非常常见。变量不需要是相同的类型,并且它们可以有各自的初始值。语法如下:
var ( <name1> <type1> = <value1> <name2> <type2> = <value2> … <nameN> <typeN> = <valueN> )
你可以有多个这种类型的声明。这是一种很好的组织相关变量的方式,使你的代码更具可读性。尽管你可以在函数中使用这种语法,但在函数中看到这种用法的情况比较少见。
练习 1.03 – 使用 var
一次声明多个变量
在这个练习中,我们将使用一个 var 语句声明多个变量,每个变量有不同的类型和初始值。然后,我们将打印每个变量的值到控制台。开始吧:
创建一个新文件夹,并在其中添加一个名为 main.go 的文件。
在 main.go 文件的顶部添加 main 包名:
package main
添加所需的导入:
import ( "fmt" "time" )
开始 var 声明:
var (
定义三个变量:
Debug bool = false LogLevel string = "info" startUpTime time.Time = time.Now()
结束 var 声明:
)
在 main() 函数中,将每个变量打印到控制台:
func main() { fmt.Println(Debug, LogLevel, startUpTime) }
保存文件。然后,在新文件夹中运行以下命令:
go run .
在这个练习中,我们使用一个 var 语句声明了三个变量。你的输出结果可能会有所不同,特别是 time.Time 变量的值会随着时间而不同,但格式是相同的。
像这样使用 var 语法是一种很好的方法来保持代码的良好组织,同时也减少了输入量。
接下来,我们将开始去掉 var 语法中的一些可选部分。
跳过声明变量时的类型或值
在实际编码中,使用完整的 var 语法并不常见。通常只有在你需要定义一个具有初始值并且需要严格控制其类型的包级变量时,才会使用完整的语法。到那时,你会明显感受到类型不匹配的问题,所以现在不必太担心。其他时候,你可以省略一些可选部分,或者使用简短的变量声明方式。
在声明变量时,你不必同时包含类型和初始值。你可以只使用其中之一;Go 会处理剩下的部分。如果声明中有类型但没有初始值,Go 会使用该类型的零值。关于零值,我们将在后面章节详细讨论。另一方面,如果有初始值而没有类型,Go 会根据你使用的字面量值来推断所需的类型。
练习 1.04 – 跳过声明变量时的类型或值
在这个练习中,我们将更新之前的练习,使其跳过变量声明中的可选初始值或类型声明。然后,我们将像之前一样将这些值打印到控制台,以展示结果是一致的。开始吧:
创建一个新文件夹,并在其中添加一个名为 main.go 的文件。
在 main.go 文件的顶部添加 main 包名:
package main
导入我们需要的包:
import ( "fmt" "time" )
开始多变量声明:
var (
在第一次练习中,布尔值的初始值是
false
,这是布尔类型的零值,因此我们可以省略其声明中的初始值:Debug bool
其余两个变量都有非零的初始值,因此我们可以省略其类型声明:
LogLevel = "info" startUpTime = time.Now()
结束 var 声明:
)
在 main() 函数中,打印每个变量的值:
func main() { fmt.Println(Debug, LogLevel, startUpTime) }
保存文件。然后,在新文件夹中运行以下命令:
go run .
输出显示即使在声明变量时没有提及类型,变量的值仍然正确
在这个练习中,我们能够更新之前的代码,使用更紧凑的变量声明方式。声明变量是你在编程中经常需要做的事情,省略这些冗余部分能让你的编码体验更好。
接下来,我们将探讨一种不能跳过任何部分的情况。
类型推断出错
有时你需要使用声明的所有部分——例如,当 Go 无法推断出你需要的正确类型时。以下是一个示例:
package main import "math/rand" func main() { var seed = 1234456789 rand.NewSource(seed) }
执行以上代码会出现错误。
问题在于 rand.NewSource 需要一个 int64 类型的变量。Go 的类型推断规则会将像我们使用的数字解释为 int 类型。后续章节中,我们会详细讨论 int 和 int64 的区别。为了解决这个问题,我们需要在声明中明确指定 int64 类型,如下所示:
package main import "math/rand" func main() { var seed int64 = 1234456789 rand.NewSource(seed) }
接下来,我们将介绍一种更快捷的变量声明方式。
短变量声明
在函数内部声明变量时,我们可以使用 := 简写。这种简写方式允许我们使声明更加简洁。它通过省略 var 关键字,并总是从需要的初始值中推断出类型来实现这一点。
练习 1.05 – 实现短变量声明
在这个练习中,我们将更新之前的代码,使用短变量声明的方式。由于短变量声明只能在函数内使用,我们会将变量从包级别作用域移动到函数内。之前 Debug 变量有类型但没有初始值,现在我们将它更改为具有初始值,因为在使用短变量声明时这是必需的。最后,我们将打印这些变量到控制台。开始吧:
创建一个新文件夹,并在其中添加一个名为 main.go 的文件。
在 main.go 文件的顶部添加 main 包名:
package main
导入我们需要的包:
import ( "fmt" "time" )
创建 main() 函数:
func main() {
使用短变量声明语法声明每个变量:
Debug := false LogLevel := "info" startUpTime := time.Now()
将变量打印到控制台:
fmt.Println(Debug, LogLevel, startUpTime) }
保存文件。然后,在新文件夹中运行以下命令:
go run .
在这个练习中,我们将之前的代码更新为使用非常简洁的变量声明方式,只要有初始值即可。
:= 简写在 Go 开发者中非常受欢迎,它是现实世界 Go 代码中最常见的变量定义方式。开发者喜欢它使代码简洁紧凑,同时仍然清晰明了。
另一个快捷方式是将多个变量声明在同一行。
使用短变量声明同时声明多个变量
你可以使用短变量声明同时声明多个变量。它们必须都在同一行,并且每个变量都必须有对应的初始值。其语法形式为 , , …, := , , …, 。变量名位于 := 左侧,并用 , 分隔。初始值位于 := 右侧,也用 , 分隔。左侧的第一个变量名对应右侧的第一个值。变量名和初始值的数量必须相等。
以下是一个使用之前练习代码的示例:
package main import ( "fmt" "time" ) func main() { Debug, LogLevel, startUpTime := false, "info", time.Now() fmt.Println(Debug, LogLevel, startUpTime) }
在实际代码中,有时会看到这样的写法。虽然这种写法有点难以阅读,但它在处理函数返回多个值时非常常见。我们将在后续章节中详细讨论这一点。
练习 1.06 – 从函数中声明多个变量
在这个练习中,我们将调用一个返回多个值的函数,并将每个值赋给一个新变量。然后,我们将这些变量打印到控制台。开始吧:
创建一个新文件夹,并在其中添加一个名为 main.go 的文件。
在 main.go 文件的顶部添加 main 包名:
package main
导入我们需要的包:
import ( "fmt" "time" )
创建一个返回三个值的函数:
func getConfig() (bool, string, time.Time) {
在函数中返回三个字面量值,每个值用 , 分隔:
return false, "info", time.Now()
关闭函数:
}
创建 main() 函数:
func main() {
使用短变量声明捕获函数返回的三个新变量的值:
Debug, LogLevel, startUpTime := getConfig()
将这三个变量打印到控制台:
fmt.Println(Debug, LogLevel, startUpTime)
关闭 main() 函数:
}
保存文件。然后,在新文件夹中运行以下命令:
go run .
在这个练习中,我们调用了一个返回多个值的函数,并使用短变量声明在一行中捕获了这些值。如果使用 var 语法,它将如下所示:
var ( Debug bool LogLevel string startUpTime time.Time ) Debug, LogLevel, startUpTime = getConfig()
短变量声明是一种使 Go 看起来像动态语言的关键特性。
不过,var 语法还有一个有用的技巧,我们将在接下来的内容中继续探索。
使用 var
一行声明多个变量
虽然短变量声明更常用,但你也可以使用 var
在一行中定义多个变量。需要注意的是,当声明类型时,所有的值必须具有相同的类型。如果你使用初始值,那么每个值可以根据字面量值推断其类型,因此可以有不同的类型。以下是一个示例:
package main import ( "fmt" "time" ) func getConfig() (bool, string, time.Time) { return false, "info", time.Now() } func main() { // 仅声明类型 var start, middle, end float32 fmt.Println(start, middle, end) // 初始值,混合类型 var name, left, right, top, bottom = "one", 1, 1.5, 2, 2.5 fmt.Println(name, left, right, top, bottom) // 也适用于函数 var Debug, LogLevel, startUpTime = getConfig() fmt.Println(Debug, LogLevel, startUpTime) }
在实际应用中,短变量声明通常会更简洁,因此 var
语法不常用于多个变量的声明。唯一的例外是当你需要声明多个相同类型的变量时,这种语法可以帮助你更好地控制类型。
非英语变量名
Go 是一个支持 UTF-8 的语言,这意味着你可以使用除拉丁字母外的其他字母来定义变量名。例如,以下代码展示了如何使用不同语言的字母作为变量名:
package main import ( "fmt" "time" ) func main() { デバッグ := false 日志级别 := "info" ይጀምሩ := time.Now() _A1_Μείγμα := "" fmt.Println(デバッグ, 日志级别, ይጀምሩ, _A1_Μείγμα) }
虽然可以这样定义,但是不建议。
修改变量的值
现在我们已经定义了变量,接下来让我们看看如何修改变量的值。修改变量的值与设置初始值的语法类似,使用 = 这样的格式。
练习 1.07 – 修改变量的值
请按照以下步骤操作:
创建一个新的文件夹,并在其中添加一个 main.go 文件。
在 main.go 中,添加 main 包名到文件的顶部:
package main
导入所需的包:
import "fmt"
创建 main() 函数:
func main() {
声明一个变量:
offset := 5
打印变量的值到控制台:
fmt.Println(offset)
修改变量的值:
offset = 10
再次打印变量的值,并关闭 main() 函数:
fmt.Println(offset) }
保存文件。在新的文件夹中,运行以下命令:
go run .
输出结果如下:
5 10
在这个例子中,我们将 offset
的值从初始值 5 修改为 10。任何使用原始值的地方,例如我们示例中的 5 和 10,你都可以使用变量。以下是如何使用变量替代原始值的示例:
package main import "fmt" var defaultOffset = 10 func main() { offset := defaultOffset fmt.Println(offset) offset = offset + defaultOffset fmt.Println(offset) }
输出结果如下:
10 20
在这个例子中,我们将 offset
的初始值设为 defaultOffset
,然后将 offset
更新为 offset + defaultOffset
。这种方法使得我们可以在代码中使用变量来替代硬编码的值,提高了代码的灵活性和可维护性。
一行中修改多个变量的值
接下来,我们将看看如何在一行中修改多个变量的值。
一次修改多个变量的值
与在一行中声明多个变量类似,你也可以在一行中同时修改多个变量的值。其语法也非常类似,格式为 , , …, = , , …, 。
练习 1.08 – 一次修改多个变量的值
在本练习中,我们将定义一些变量,并使用一行语句来修改它们的值。然后,我们会打印出这些变量的新值。让我们开始吧:
创建一个新的文件夹,并在其中添加一个 main.go 文件。
在 main.go 中,添加 main 包名到文件的顶部:
package main
导入所需的包:
import "fmt"
创建 main() 函数:
func main() {
声明我们的变量并初始化值:
query, limit, offset := "bat", 10, 0
使用一行语句修改每个变量的值:
query, limit, offset = "ball", offset, 20
打印这些变量的值到控制台,并关闭 main() 函数:
fmt.Println(query, limit, offset) }
保存文件。在新的文件夹中,运行以下命令:
go run .
输出结果如下,显示了一行语句中修改后的变量值:
ball 0 20
在本练习中,我们成功地在一行中修改了多个变量的值。这种方法也可以用于函数调用,就像变量声明一样。不过,你需要小心使用这种特性,确保代码首先易于阅读和理解。如果使用一行语句使得代码难以理解,那么分多行写代码可能会更清晰。
接下来,我们将探讨操作符是什么,以及它们如何被用来以有趣的方式改变你的变量。