变量与类型:构建你的第一个Go程序
欢迎来到Go语言的世界。编程的本质是处理数据,而我们与数据的第一次亲密接触,始于理解"变量"和"类型"。本文将引导你编写第一个Go程序,并在此过程中,为你建立一个关于Go如何看待和组织数据的坚实心智模型。
让我们忘掉枯燥的定义列表,从一段最简单的代码开始。
你的第一个Go程序:hello.go
在你的工作区,创建一个名为 hello.go
的文件,并输入以下内容:
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
package main
: 声明这个文件属于main
包。一个可执行程序必须有一个main
包。import "fmt"
: 导入一个名为fmt
的标准库包。fmt
提供了格式化输入输出的功能,比如在屏幕上打印文本。func main()
: 定义一个名为main
的函数。这是我们程序的入口,当你运行程序时,main
函数里的代码会被执行。fmt.Println(...)
: 调用fmt
包里的Println
函数,将 "Hello, World!" 这个字符串打印到控制台。
现在,打开终端,进入文件所在的目录,运行它:
$ go run hello.go
Hello, World!
恭喜!你已经成功运行了你的第一个Go程序。更重要的是,你已经接触到了Go的第一个基本类型:字符串(string)。
变量:给数据一个名字
程序很少只处理静态的文本。我们通常需要存储和操作数据。变量(Variable) 就是内存中一个存储数据的命名空间。
让我们修改一下程序,使用变量来存储我们的问候语:
package main
import "fmt"
func main() {
var greeting string = "Hello, Gopher!"
fmt.Println(greeting)
}
这里发生了几件事:
var greeting string
: 我们声明了一个变量。var
是一个关键字,表示我们要声明一个变量。greeting
是我们给这个变量起的名字。string
是我们告诉Go编译器,这个变量只能存储字符串类型的数据。
= "Hello, Gopher!"
: 我们初始化了这个变量,给它赋了一个初始值。
这体现了Go作为一门**静态类型(Static Typing)**语言的核心特征:变量的类型在编译时就已确定,并且永远不能改变。你不能把一个数字赋给一个 string
类型的变量,这保证了类型安全,减少了运行时错误。
类型推断与短变量声明
Go的编译器很聪明。在很多情况下,它能根据你提供的值推断出变量的类型。这让我们可以使用一种更简洁的声明方式。
重写上面的代码:
package main
import "fmt"
func main() {
// Go编译器看到 "Hello, Gopher!" 就知道 greeting 是 string 类型
var greeting = "Hello, Gopher!"
fmt.Println(greeting)
}
在函数内部,我们还有一种更常用、更简洁的方式:短变量声明 :=
。
package main
import "fmt"
func main() {
// := 结合了声明和初始化,var 关键字被省略
// 这是在函数内部最常用的方式
greeting := "Hello, Gopher!"
fmt.Println(greeting)
}
注意: 短变量声明 :=
只能在函数内部使用。对于包级别的变量,必须使用 var
关键字。
Go的核心类型:构建程序的基石
现在我们已经知道如何声明变量,让我们来认识一下Go语言提供的核心"建筑材料"。
1. 布尔型 (bool)
布尔型只有两个值:true
或 false
。它通常用于条件判断。
var isReady bool = true
canProceed := !isReady // "!" 是逻辑非操作符,结果是 false
fmt.Println(canProceed)
2. 数字类型 (Numeric Types)
Go提供了丰富的数字类型来满足不同的精度和平台需求。
整型 (Integer)
int
: 默认的整数类型。在32位系统上是32位,在64位系统上是64位。在不确定时,优先使用int
。int8
,int16
,int32
,int64
: 固定大小的有符号整数。uint
,uint8
,uint16
,uint32
,uint64
: 无符号整数,不能表示负数。byte
是uint8
的别名。uintptr
: 一种特殊的无符号整数,用于存储指针的地址,常用于底层编程。
var score int = 100
playerCount := 10
// 不同类型的整数不能直接进行运算
// 下面的代码会编译错误: invalid operation: score + int32(playerCount) (mismatched types int and int32)
// var totalScore = score + int32(playerCount)
// 必须进行显式类型转换
var totalScore = score + int(playerCount)
fmt.Println(totalScore)
类型转换是Go静态类型哲学的重要体现:类型安全由你(开发者)来保证,编译器不会做任何隐式的转换。
浮点型 (Floating-Point)
float32
,float64
: 32位和64位的浮点数,用于表示小数。在不确定时,优先使用float64
。
var price float64 = 99.99
taxRate := 0.08
totalPrice := price * (1 + taxRate)
fmt.Println(totalPrice)
复数 (Complex)
complex64
,complex128
: 用于科学计算和工程领域。
3. 字符串 (string)
我们已经见过字符串了。Go的字符串是不可变的(immutable),由一系列 byte
(UTF-8编码) 组成。一旦创建,你不能修改字符串的某个字符。
path := "/usr/local/bin"
// path[0] = 'c' // 这会产生编译错误
// 你可以基于原字符串创建新的字符串
newPath := "C:" + path[1:] // 字符串拼接和切片操作
fmt.Println(newPath)
零值 (Zero Value)
Go有一个重要的概念:任何变量在声明后,都会被自动初始化为其类型的"零值"。这可以防止未初始化变量导致的问题。
- 数字类型:
0
- 布尔类型:
false
- 字符串类型:
""
(空字符串) - 指针、接口、切片、映射、通道、函数类型:
nil
var playerCount int
var price float64
var greeting string
var isReady bool
// 打印它们的值,看看是不是零值
// Printf 是格式化打印函数,%v 代表默认格式,%q 带引号的字符串
fmt.Printf("playerCount: %v, price: %v, greeting: %q, isReady: %v\n",
playerCount, price, greeting, isReady)
// 输出:
// playerCount: 0, price: 0, greeting: "", isReady: false
这个特性让你的代码更安全、更可预测。
下一步
你已经掌握了Go语言中最基本,也是最重要的概念:如何通过变量和类型来描述和存储数据。这是构建任何复杂逻辑的起点。
在下一篇文章中,我们将学习如何使用 数组(Array)、切片(Slice)和映射(Map) 来组织和管理这些基本数据,从处理单个值升级到处理数据集合。