Go语言变量与数据类型完全指南

概述

Go语言以其简洁的类型系统著称,变量声明方式多样,数据类型清晰明了。本文详细介绍Go语言中的变量声明、基本数据类型、类型转换以及可见性规则,帮助读者打下坚实的类型基础。

一、变量声明

1.1 var 声明

标准的变量声明使用 var 关键字:

Go 复制代码
// 基本语法
var name string = "张三"
var age int = 25
var isStudent bool = true
​
// 类型推断(省略类型)
var name = "张三"    // 推断为 string
var age = 25         // 推断为 int
var isStudent = true // 推断为 bool
​
// 声明多个变量
var (
    name string
    age  int
    city string = "北京"
)

1.2 短变量声明(:=)

在函数内部,可以使用 := 进行短变量声明:

Go 复制代码
func main() {
    name := "Go语言"           // 等价于 var name string = "Go语言"
    version := 1.22            // 等价于 var version int = 1.22
    price := 99.9              // 等价于 var price float64 = 99.9
    
    fmt.Println(name, version, price)
}

重要规则:

  • := 只能在函数内部使用,不能用于全局变量声明

  • 左侧至少有一个变量是新建的,不能全是已存在的变量

复制代码
// 正确示例
a, b := 1, 2      // 两个都是新建
a, c := 1, 3      // a已存在,c新建
​
// 错误示例
a, b := 1, 2      // 错误:没有新变量

1.3 常量声明

常量使用 const 关键字,值在编译时确定:

Go 复制代码
const Pi float64 = 3.14159
const AppName = "MyApp"              // 类型推断
const (
    StatusOK    = 200
    StatusNotFound = 404
    StatusError = 500
)
​
// iota:常量计数器,用于生成枚举值
const (
    Sunday = iota  // 0
    Monday         // 1
    Tuesday        // 2
    Wednesday      // 3
    Thursday       // 4
    Friday         // 5
    Saturday       // 6
)

1.4 零值机制

Go语言中,未初始化的变量会自动赋零值:

类型 零值
数值类型(int, float) 0
布尔类型 bool false
字符串 string ""(空字符串)
指针、切片、map、channel、interface nil
Go 复制代码
func main() {
    var i int
    var f float64
    var b bool
    var s string
    var arr []int
    
    fmt.Printf("int零值: %d\n", i)
    fmt.Printf("float零值: %f\n", f)
    fmt.Printf("bool零值: %t\n", b)
    fmt.Printf("string零值: '%s'\n", s)
    fmt.Printf("slice零值: %v (nil: %t)\n", arr, arr == nil)
}

输出:

复制代码
int零值: 0
float零值: 0.000000
bool零值: false
string零值: ''
slice零值: [] (nil: true)

二、基本数据类型

2.1 整数类型

Go的整数类型分为有符号和无符号两大类:

有符号整数:

类型 描述 范围
int8 8位有符号 -128 ~ 127
int16 16位有符号 -32768 ~ 32767
int32 32位有符号 -2147483648 ~ 2147483647
int64 64位有符号 -9223372036854775808 ~ 9223372036854775807
int 平台相关(32/64位) 取决于平台

无符号整数:

类型 描述 范围
uint8 8位无符号 0 ~ 255
uint16 16位无符号 0 ~ 65535
uint32 32位无符号 0 ~ 4294967295
uint64 64位无符号 0 ~ 18446744073709551615
uint 平台相关 取决于平台
byte uint8 的别名 0 ~ 255
rune int32 的别名(Unicode码点) -2147483648 ~ 2147483647
Go 复制代码
func main() {
    // 有符号整数
    var a int8 = 127
    var b int16 = -128
    var c int32 = 2147483647
    var d int64 = -9223372036854775808
    
    // 无符号整数
    var e uint8 = 255
    var f uint16 = 65535
    
    // byte 和 rune
    var g byte = 65          // ASCII 'A'
    var h rune = '中'         // Unicode码点
    
    fmt.Printf("int8: %d\n", a)
    fmt.Printf("int16: %d\n", b)
    fmt.Printf("byte: %c (ASCII 65)\n", g)
    fmt.Printf("rune: %c (Unicode)\n", h)
}

2.2 浮点数类型

类型 描述 精度
float32 32位浮点数 约7位十进制数字
float64 64位浮点数 约15位十进制数字(推荐使用
Go 复制代码
func main() {
    var a float32 = 3.1415926
    var b float64 = 3.141592653589793
    
    fmt.Printf("float32: %f\n", a)
    fmt.Printf("float32: %.6f\n", a)
    fmt.Printf("float64: %.15f\n", b)
    
    // 科学计数法
    fmt.Printf("float64科学计数: %e\n", b)
    
    // 特殊值
    fmt.Printf("无穷大: %f\n", math.Inf(1))
    fmt.Printf("负无穷: %f\n", math.Inf(-1))
    fmt.Printf("NaN: %f\n", math.NaN())
}

2.3 复数类型

Go支持复数运算:

Go 复制代码
func main() {
    var c1 complex64 = 1 + 2i
    var c2 complex128 = 3 + 4i
    
    fmt.Printf("c1: %v\n", c1)
    fmt.Printf("c2: %v\n", c2)
    fmt.Printf("c1 + c2 = %v\n", c1 + c2)
    fmt.Printf("c1 * c2 = %v\n", c1 * c2)
    fmt.Printf("real(c1) = %f, imag(c1) = %f\n", real(c1), imag(c1))
}

2.4 字符串类型

Go字符串是UTF-8编码的不可变字节序列:

Go 复制代码
func main() {
    s1 := "Hello, Go!"
    s2 := "你好,Go语言!"
    
    fmt.Println(s1)
    fmt.Println(s2)
    
    // 字符串长度(字节数)
    fmt.Printf("s1字节长度: %d\n", len(s1))
    fmt.Printf("s2字节长度: %d\n", len(s2))
    
    // 字符个数(rune数)
    fmt.Printf("s2字符个数: %d\n", len([]rune(s2)))
    
    // 访问单个字节
    fmt.Printf("s1[0] = %c (字节值: %d)\n", s1[0], s1[0])
}

2.5 布尔类型

布尔类型只有两个值:truefalse

Go 复制代码
func main() {
    var a bool = true
    var b bool = false
    
    // 短路求值
    c := a && b  // false(a为true,但b为false)
    d := a || b  // true(a为true,无需计算b)
    
    fmt.Printf("a && b = %t\n", c)
    fmt.Printf("a || b = %t\n", d)
    fmt.Printf("!a = %t\n", !a)
}

三、类型转换

Go语言没有隐式类型转换,必须显式转换:

3.1 数值类型转换

Go 复制代码
func main() {
    // int 转 float
    var i int = 42
    var f float64 = float64(i)
    fmt.Printf("int->float64: %f\n", f)
    
    // float 转 int(丢失小数部分)
    var f2 float64 = 3.99
    var i2 int = int(f2)
    fmt.Printf("float64->int: %d (截断)\n", i2)
    
    // int8, int16, int32, int64 互转
    var i64 int64 = 1000
    var i32 int32 = int32(i64)
    var i16 int16 = int16(i32)
    var i8 int8 = int8(i16)
    fmt.Printf("int64->int8: %d\n", i8)
}

⚠️ 溢出问题:

Go 复制代码
func main() {
    var i int8 = 127
    var i2 int8 = int8(i + 1)  // 溢出,结果为-128
    fmt.Printf("int8溢出: %d\n", i2)
    
    var u uint8 = 255
    var u2 uint8 = u + 1       // 溢出,结果为0
    fmt.Printf("uint8溢出: %d\n", u2)
}

3.2 字符串与字节切片互转

Go 复制代码
func main() {
    // string 转 []byte
    s := "Hello"
    b := []byte(s)
    fmt.Printf("[]byte: %v\n", b)
    
    // []byte 转 string
    b2 := []byte{72, 101, 108, 108, 111}
    s2 := string(b2)
    fmt.Printf("string: %s\n", s2)
    
    // string 转 []rune(处理中文)
    s3 := "你好"
    r := []rune(s3)
    fmt.Printf("[]rune: %v (Unicode码点)\n", r)
    fmt.Printf("字符个数: %d\n", len(r))
    
    // []rune 转 string
    r2 := []rune{0x4E2D, 0x6587}
    s4 := string(r2)
    fmt.Printf("string: %s\n", s4)
}

3.3 strconv 包转换

Go 复制代码
import "strconv"
​
func main() {
    // 字符串转数值
    i, _ := strconv.Atoi("42")
    fmt.Printf("Atoi: %d\n", i)
    
    f, _ := strconv.ParseFloat("3.14", 64)
    fmt.Printf("ParseFloat: %.2f\n", f)
    
    b, _ := strconv.ParseBool("true")
    fmt.Printf("ParseBool: %t\n", b)
    
    // 数值转字符串
    s1 := strconv.Itoa(42)
    s2 := strconv.FormatFloat(3.14, 'f', 2, 64)
    s3 := strconv.FormatBool(true)
    
    fmt.Printf("Itoa: %s\n", s1)
    fmt.Printf("FormatFloat: %s\n", s2)
    fmt.Printf("FormatBool: %s\n", s3)
}

四、可见性规则

Go语言使用首字母大小写来控制标识符的可见性:

Go 复制代码
package mypackage
​
import "fmt"
​
// MyPublicFunc 首字母大写,可被其他包导出
func MyPublicFunc() {
    fmt.Println("我是公开函数")
}
​
// myPrivateFunc 首字母小写,仅限本包内使用
func myPrivateFunc() {
    fmt.Println("我是私有函数")
}
​
// MyPublicVar 公开变量
var MyPublicVar = 100
​
// myPrivateVar 私有变量
var myPrivateVar = 200
​
// MyPublicType 公开结构体
type MyPublicType struct {
    Name  string  // 公开字段
    age  int      // 私有字段
}

规则总结:

  • 首字母大写:导出标识符,可被其他包访问

  • 首字母小写:未导出标识符,仅限本包内访问

五、命名规范

5.1 变量命名

Go语言推崇简洁、有意义的命名:

Go 复制代码
// ✅ 推荐:简洁清晰
userName := "张三"
isActive := true
itemCount := 0
​
// ❌ 避免:过于简短或无意义
x := "张三"       // x是什么?
a := 1            // a是什么?
data := ""        // 什么数据?
​
// ❌ 避免:中文拼音
xingming := "张三"

5.2 常量命名

Go 复制代码
// 常量组命名规范
const (
    StatusOK       = 200
    StatusNotFound = 404
    StatusError    = 500
)
​
// 枚举类型通常使用 iota
const (
    Monday    = iota
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
    Sunday
)

5.3 包命名

Go 复制代码
// ✅ 推荐:简短、全小写、不含下划线
import (
    "fmt"
    "strings"
    "os/user"
)
​
// ❌ 避免:下划线、混合大小写
// import "my_package"     // 下划线不推荐
// import "MyPackage"      // 混合大小写不推荐

六、代码规范检查

使用 go vetgofmt 保持代码规范:

Go 复制代码
# 格式化代码
go fmt ./...
​
# 检查代码问题
go vet ./...
​
# 使用 golangci-lint(需安装)
golangci-lint run

总结

本文详细介绍了Go语言的变量声明、数据类型、类型转换和可见性规则。需要牢记:

  1. 变量声明var 声明可带类型,:= 用于函数内短声明

  2. 数据类型:数值、字符串、布尔、rune/byte

  3. 类型转换:必须显式转换,不存在隐式转换

  4. 可见性:首字母大写为导出,小写为私有

思考题:

  1. var a int = 3.14 为什么不能编译通过?

  2. 如何正确判断中文字符串的长度?

  3. 为什么推荐使用 float64 而不是 float32?


📚 下一篇文章我们将深入讲解 Go 语言的运算符与控制流程,敬请期待!

相关推荐
wjs20242 小时前
Ruby JSON
开发语言
初心未改HD2 小时前
Go语言环境搭建与第一个程序详解
开发语言·后端·golang
minji...2 小时前
Linux 网络套接字编程(五)TCP 回声服务器的实现(单进程(单线程)/多进程/多线程/线程池四个版本)
linux·服务器·开发语言·网络·c++·tcp/ip·算法
嘻嘻哈哈樱桃2 小时前
牛客经典101题题解集--堆/栈/队列
java·开发语言·算法
csbysj20202 小时前
Memcached append 命令详解
开发语言
故事还在继续吗2 小时前
C++内存模型
开发语言·c++·内存
Tairitsu_H2 小时前
C++:构造函数与初始化列表详解
开发语言·c++·构造函数
keep intensify2 小时前
MIT 6.824 lab3B/C
分布式·后端·golang
琪露诺大湿2 小时前
VeloQueue-测试报告
java·开发语言·消息队列·单元测试·项目·测试报告