基础语法(上):变量声明、常量与iota、基本数据类型、类型转换

说实话,每次带新人入门Go语言,我都是从变量声明开始讲起的。为什么?因为Go在这块的设计,跟Java、Python都不太一样。你上手写几行代码就能感受到——这语言是真的「简洁」。

好,咱们直接开干。

1. 变量声明:var 与 :=

Go语言里声明变量,主要有两种方式。我个人的习惯是:能用短声明就用短声明,除非有特殊需求。

1.1 使用 var 关键字

这是最传统的写法,跟C语言有点像,但类型写在变量名后面。

var name string = "张三"
var age int = 25
var isStudent bool = true

你也可以省略类型,让编译器自己推断:

var name = "张三"   // 自动推断为 string
var age = 25        // 自动推断为 int

嗯,这里要注意:如果你只声明不赋值,必须带上类型。否则编译器会懵——「你让我猜类型,又不给我值,我怎么猜?」

var name string   // 正确,name 默认值为 ""
var age           // 编译错误:no new variables on left side of :=

1.2 使用 := 短变量声明

这是Go最让我舒服的特性之一。在函数内部,你可以直接用 := 来声明并初始化变量:

name := "张三"
age := 25
isStudent := true

你看,代码是不是清爽多了?我在项目中写业务逻辑时,几乎90%的场景都用 :=。但有个坑——短声明只能在函数内部使用。包级别的变量,还是得老老实实用 var

我曾经踩过的坑:有一次在全局作用域里写了 name := "张三",编译直接报错。当时我还纳闷:「这语法不是挺常见的吗?」后来才意识到——短声明是函数内专用的。

1.3 多变量声明

Go支持一次声明多个变量,这在处理函数返回值时特别有用:

var x, y int = 1, 2
a, b := "hello", true

我个人觉得,这种写法在解构赋值时特别优雅。比如调用一个返回多个值的函数:

result, err := doSomething()

你想想看,如果每个返回值都要单独声明,那代码得多啰嗦。

2. 常量与 iota

常量在Go里用 const 关键字声明。跟变量不同,常量一旦定义就不能修改。这个大家都懂,我就不多说了。

2.1 普通常量

const Pi = 3.14159
const MaxRetries = 3

常量也可以分组声明:

const (
    StatusOK = 200
    StatusNotFound = 404
    StatusServerError = 500
)

2.2 iota:Go的枚举神器

这个 iota 是我觉得Go里最巧妙的设计之一。它是个常量生成器,在 const 块里每出现一次,值就自动加1。

const (
    Sunday = iota   // 0
    Monday          // 1
    Tuesday         // 2
    Wednesday       // 3
    Thursday        // 4
    Friday          // 5
    Saturday        // 6
)

说白了,iota 就是帮你省去手动编号的麻烦。我在项目中定义日志级别时经常用:

const (
    LevelDebug = iota
    LevelInfo
    LevelWarn
    LevelError
)

你还可以玩点花样,比如跳过某些值:

const (
    _ = iota      // 0,被忽略
    KB = 1 << (10 * iota)  // 1 << 10 = 1024
    MB                       // 1 << 20 = 1048576
    GB                       // 1 << 30 = 1073741824
)
小技巧:如果你想让枚举从1开始,可以这样写:First = iota + 1。这样第一个值就是1,而不是0。

3. 基本数据类型

Go是强类型语言,每个变量都有明确的类型。常用的基本类型就这几种:

类型 说明 默认值
int 整数,根据平台可能是32位或64位 0
float64 浮点数,常用这个 0.0
string 字符串,不可变 ""
bool 布尔值 false

3.1 int 类型

Go的整数类型分得很细:int8int16int32int64,还有无符号的 uint 系列。但日常开发中,我基本只用 int。为什么?因为够用,而且不用操心位数问题。

var a int = 42
var b int64 = 42  // 这是不同的类型!

嗯,这里有个坑:intint64 不是同一个类型。你不能直接把 int 赋值给 int64,必须做类型转换。我刚开始学Go时就被这个坑过。

3.2 float 类型

浮点数有 float32float64。我建议你直接用 float64,精度更高,而且很多标准库函数都默认用这个。

var price float64 = 19.99
var tax float32 = 0.08  // 精度较低,不推荐

3.3 string 类型

字符串在Go里是UTF-8编码的,支持各种语言字符。你可以用双引号或反引号:

s1 := "Hello, 世界"
s2 := `多行
字符串
直接写`

反引号的好处是:里面的内容原样输出,不需要转义。我在写SQL语句或JSON模板时特别喜欢用。

3.4 bool 类型

布尔值只有 truefalse。注意,Go里不能把整数当布尔用——这是跟C语言最大的区别。

var flag bool = true
if flag {   // 正确
    fmt.Println("true")
}
// if 1 {   // 编译错误!1 不能当作布尔值
//     fmt.Println("true")
// }

4. 类型转换

Go是强类型语言,类型转换必须显式进行。你不能像Python那样随意混用类型。

4.1 基本语法

类型转换的写法是 T(v),把值 v 转换为类型 T

var a int = 42
var b float64 = float64(a)   // int → float64
var c int = int(b)            // float64 → int,小数部分被截断

我曾经在项目中遇到过一个问题:把一个 float64 转成 int 时,小数部分直接丢了,导致计算结果偏差。后来我改用 math.Round 先四舍五入再转换。

4.2 字符串与数字的转换

这个稍微麻烦点,需要借助 strconv 包:

import "strconv"

// 字符串转整数
s := "42"
n, err := strconv.Atoi(s)
if err != nil {
    // 处理错误
}

// 整数转字符串
s2 := strconv.Itoa(42)

// 字符串转浮点数
f, err := strconv.ParseFloat("3.14", 64)
注意:类型转换不是万能的。你不能把 string 直接转成 int,也不能把 bool 转成 int。Go在这块非常严格——我觉得这是好事,能避免很多隐晦的bug。

4.3 类型断言(接口相关)

这个稍微进阶一点,但我觉得有必要提一下。当你有一个接口类型的值时,可以用类型断言来获取其具体类型:

var i interface{} = "hello"
s, ok := i.(string)
if ok {
    fmt.Println(s)  // 输出 "hello"
}

你想想看,如果没有类型断言,你怎么知道接口里装的是什么类型?

5. 避坑指南

最后,我总结几个新手容易踩的坑:

  • 变量声明后必须使用:Go编译器会报错,这是Go的设计哲学——「没用的代码就是垃圾」。
  • 短声明不能用于全局:包级别变量只能用 var
  • 类型转换必须显式:别指望Go帮你自动转,它不会。
  • iota 从0开始:如果你需要从1开始,记得加1。

好了,这一章的内容就到这里。下一章我们会深入控制流——if、for、switch这些。到时候我会分享一些我在实际项目中用到的骚操作,敬请期待。