Go语言基础语法:变量、常量与数据类型
目录
前言
在上一篇文章中,我们了解了Go语言的发展历程和环境搭建。今天我们将深入学习Go语言的基础语法,重点掌握变量、常量和数据类型的使用。这些知识是Go语言编程的基石,掌握好这些内容将为后续的学习奠定坚实的基础。
Go语言作为一门强类型、静态编译的语言,在变量和类型处理上有着独特的设计哲学。它既保持了C语言的高效性,又提供了现代编程语言的便利性。让我们一起来探索Go语言在这方面的精妙设计。
变量声明的多种方式
1. 使用var关键字声明
Go语言提供了多种变量声明方式,其中最基础的是使用var
关键字:
go
package main
import "fmt"
func main() {
// 方式1:声明并初始化
var name string = "张三"
var age int = 25
var height float64 = 175.5
// 方式2:先声明,后赋值
var email string
email = "zhangsan@example.com"
// 方式3:类型推断
var city = "北京" // Go会自动推断为string类型
var population = 21540000 // 自动推断为int类型
// 方式4:批量声明
var (
username string = "admin"
password string = "123456"
isActive bool = true
)
fmt.Printf("姓名: %s, 年龄: %d, 身高: %.1f\n", name, age, height)
fmt.Printf("邮箱: %s, 城市: %s, 人口: %d\n", email, city, population)
fmt.Printf("用户名: %s, 是否激活: %t\n", username, isActive)
}
2. 短变量声明(:=)
Go语言最具特色的是短变量声明操作符:=
,它让代码更加简洁:
go
package main
import "fmt"
func main() {
// 短变量声明,只能在函数内使用
name := "李四"
age := 30
salary := 8500.50
married := true
// 多变量同时声明
x, y, z := 1, 2, 3
// 函数返回值的接收
result, err := divide(10, 2)
if err != nil {
fmt.Println("错误:", err)
return
}
fmt.Printf("姓名: %s, 年龄: %d, 薪资: %.2f, 已婚: %t\n",
name, age, salary, married)
fmt.Printf("坐标: (%d, %d, %d)\n", x, y, z)
fmt.Printf("除法结果: %.2f\n", result)
}
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("除数不能为零")
}
return a / b, nil
}
3. 变量的零值
Go语言中,未初始化的变量会被赋予对应类型的零值:
go
package main
import "fmt"
func main() {
var (
intVar int // 0
floatVar float64 // 0.0
boolVar bool // false
stringVar string // ""
pointerVar *int // nil
)
fmt.Printf("int零值: %d\n", intVar)
fmt.Printf("float64零值: %f\n", floatVar)
fmt.Printf("bool零值: %t\n", boolVar)
fmt.Printf("string零值: '%s'\n", stringVar)
fmt.Printf("pointer零值: %v\n", pointerVar)
// 判断字符串是否为空
if stringVar == "" {
fmt.Println("字符串变量为空")
}
// 判断指针是否为nil
if pointerVar == nil {
fmt.Println("指针变量为nil")
}
}
Go语言基本数据类型详解
1. 数值类型
Go语言提供了丰富的数值类型,让我们详细了解:
go
package main
import (
"fmt"
"unsafe"
)
func main() {
// 整数类型
var int8Var int8 = 127 // -128 到 127
var int16Var int16 = 32767 // -32768 到 32767
var int32Var int32 = 2147483647
var int64Var int64 = 9223372036854775807
// 无符号整数类型
var uint8Var uint8 = 255 // 0 到 255
var uint16Var uint16 = 65535 // 0 到 65535
var uint32Var uint32 = 4294967295
var uint64Var uint64 = 18446744073709551615
// 浮点数类型
var float32Var float32 = 3.14159
var float64Var float64 = 3.141592653589793
// 复数类型
var complex64Var complex64 = 1 + 2i
var complex128Var complex128 = 2 + 3i
// 其他数值类型
var intVar int = 42 // 根据系统位数决定大小
var uintVar uint = 42 // 根据系统位数决定大小
var byteVar byte = 255 // uint8的别名
var runeVar rune = 'A' // int32的别名,表示Unicode码点
// 打印类型大小
fmt.Printf("int8大小: %d字节\n", unsafe.Sizeof(int8Var))
fmt.Printf("int16大小: %d字节\n", unsafe.Sizeof(int16Var))
fmt.Printf("int32大小: %d字节\n", unsafe.Sizeof(int32Var))
fmt.Printf("int64大小: %d字节\n", unsafe.Sizeof(int64Var))
fmt.Printf("float32大小: %d字节\n", unsafe.Sizeof(float32Var))
fmt.Printf("float64大小: %d字节\n", unsafe.Sizeof(float64Var))
// 打印值
fmt.Printf("复数64: %v\n", complex64Var)
fmt.Printf("复数128: %v\n", complex128Var)
fmt.Printf("rune值: %c (Unicode: %d)\n", runeVar, runeVar)
}
2. 字符串和字符类型
go
package main
import (
"fmt"
"unicode/utf8"
)
func main() {
// 字符串类型
var str1 string = "Hello, 世界!"
str2 := `这是一个原始字符串
可以包含换行符
和特殊字符: \n \t`
// 字符类型(rune)
var char1 rune = 'A'
var char2 rune = '世'
var char3 rune = '🌟'
// 字节类型(byte)
var b1 byte = 'A' // ASCII字符
// 字符串操作
fmt.Printf("字符串1: %s\n", str1)
fmt.Printf("字符串1长度(字节): %d\n", len(str1))
fmt.Printf("字符串1长度(字符): %d\n", utf8.RuneCountInString(str1))
fmt.Printf("原始字符串:\n%s\n", str2)
// 字符信息
fmt.Printf("字符A: %c, Unicode: %d, 字节: %d\n", char1, char1, char1)
fmt.Printf("字符世: %c, Unicode: %d\n", char2, char2)
fmt.Printf("字符🌟: %c, Unicode: %d\n", char3, char3)
fmt.Printf("字节A: %c, 值: %d\n", b1, b1)
// 字符串遍历
fmt.Println("按字节遍历:")
for i := 0; i < len(str1); i++ {
fmt.Printf("索引%d: %c\n", i, str1[i])
}
fmt.Println("按字符遍历:")
for i, r := range str1 {
fmt.Printf("索引%d: %c\n", i, r)
}
}
3. 布尔类型
go
package main
import "fmt"
func main() {
// 布尔类型只有两个值:true和false
var isActive bool = true
var isComplete bool = false
var isReady bool // 零值为false
// 布尔运算
result1 := isActive && isComplete // 逻辑与
result2 := isActive || isComplete // 逻辑或
result3 := !isActive // 逻辑非
fmt.Printf("isActive: %t\n", isActive)
fmt.Printf("isComplete: %t\n", isComplete)
fmt.Printf("isReady: %t\n", isReady)
fmt.Printf("AND运算: %t\n", result1)
fmt.Printf("OR运算: %t\n", result2)
fmt.Printf("NOT运算: %t\n", result3)
// 条件判断
age := 18
if age >= 18 {
fmt.Println("已成年")
} else {
fmt.Println("未成年")
}
// 复杂条件
score := 85
if score >= 90 {
fmt.Println("优秀")
} else if score >= 80 {
fmt.Println("良好")
} else if score >= 60 {
fmt.Println("及格")
} else {
fmt.Println("不及格")
}
}
常量定义和iota的使用
1. 常量的基本使用
go
package main
import "fmt"
func main() {
// 单个常量定义
const PI float64 = 3.14159265359
const COMPANY_NAME string = "科技有限公司"
const MAX_USERS = 1000 // 类型推断
// 批量常量定义
const (
StatusOK = 200
StatusError = 500
StatusNotFound = 404
)
// 无类型常量(更灵活)
const MULTIPLIER = 10
fmt.Printf("圆周率: %.10f\n", PI)
fmt.Printf("公司名称: %s\n", COMPANY_NAME)
fmt.Printf("最大用户数: %d\n", MAX_USERS)
// 常量可以用于不同的数值类型
var intVal int = MULTIPLIER
var floatVal float64 = MULTIPLIER
var complexVal complex128 = MULTIPLIER
fmt.Printf("整数: %d, 浮点数: %.1f, 复数: %.1f\n",
intVal, floatVal, complexVal)
}
2. iota枚举器的强大功能
go
package main
import "fmt"
func main() {
// 基本iota使用
const (
Monday = iota // 0
Tuesday = iota // 1
Wednesday = iota // 2
Thursday = iota // 3
Friday = iota // 4
Saturday = iota // 5
Sunday = iota // 6
)
// 简化写法
const (
January = iota + 1 // 1
February // 2
March // 3
April // 4
May // 5
June // 6
July // 7
August // 8
September // 9
October // 10
November // 11
December // 12
)
// 跳过某些值
const (
_ = iota // 跳过0
KB = 1 << (10 * iota) // 1024
MB // 1048576
GB // 1073741824
TB // 1099511627776
)
// 复杂的iota表达式
const (
ReadPermission = 1 << iota // 1 (二进制: 001)
WritePermission // 2 (二进制: 010)
ExecutePermission // 4 (二进制: 100)
)
fmt.Printf("星期一: %d, 星期天: %d\n", Monday, Sunday)
fmt.Printf("一月: %d, 十二月: %d\n", January, December)
fmt.Printf("1KB = %d字节\n", KB)
fmt.Printf("1MB = %d字节\n", MB)
fmt.Printf("1GB = %d字节\n", GB)
// 权限组合使用
fullPermission := ReadPermission | WritePermission | ExecutePermission
fmt.Printf("读权限: %d, 写权限: %d, 执行权限: %d\n",
ReadPermission, WritePermission, ExecutePermission)
fmt.Printf("完整权限: %d (二进制: %b)\n", fullPermission, fullPermission)
}
3. 实际应用:状态机和配置常量
go
package main
import "fmt"
// HTTP状态码
const (
StatusContinue = 100
StatusSwitchingProtocols = 101
StatusOK = 200
StatusCreated = 201
StatusAccepted = 202
StatusNoContent = 204
StatusMovedPermanently = 301
StatusFound = 302
StatusBadRequest = 400
StatusUnauthorized = 401
StatusForbidden = 403
StatusNotFound = 404
StatusInternalServerError = 500
StatusBadGateway = 502
StatusServiceUnavailable = 503
)
// 用户状态
const (
UserStatusInactive = iota
UserStatusActive
UserStatusSuspended
UserStatusDeleted
)
// 订单状态
const (
OrderStatusPending = iota + 1 // 从1开始
OrderStatusPaid
OrderStatusShipped
OrderStatusDelivered
OrderStatusCancelled
)
func main() {
// 模拟用户状态管理
userStatus := UserStatusActive
switch userStatus {
case UserStatusInactive:
fmt.Println("用户未激活")
case UserStatusActive:
fmt.Println("用户已激活")
case UserStatusSuspended:
fmt.Println("用户已暂停")
case UserStatusDeleted:
fmt.Println("用户已删除")
default:
fmt.Println("未知状态")
}
// 模拟HTTP响应处理
responseCode := StatusNotFound
if responseCode >= 200 && responseCode < 300 {
fmt.Println("请求成功")
} else if responseCode >= 400 && responseCode < 500 {
fmt.Println("客户端错误")
} else if responseCode >= 500 {
fmt.Println("服务器错误")
}
// 订单状态流转
orderStatus := OrderStatusPending
fmt.Printf("当前订单状态: %d\n", orderStatus)
// 状态升级
orderStatus = OrderStatusPaid
fmt.Printf("订单已支付,状态: %d\n", orderStatus)
}
类型转换和类型推断
1. 显式类型转换
go
package main
import (
"fmt"
"strconv"
)
func main() {
// 数值类型间的转换
var intVal int = 42
var floatVal float64 = float64(intVal)
var float32Val float32 = float32(floatVal)
var uintVal uint = uint(intVal)
fmt.Printf("原始int: %d\n", intVal)
fmt.Printf("转换为float64: %.2f\n", floatVal)
fmt.Printf("转换为float32: %.2f\n", float32Val)
fmt.Printf("转换为uint: %d\n", uintVal)
// 注意:不同大小的整数类型转换
var bigInt int64 = 1000000
var smallInt int8 = int8(bigInt) // 可能会溢出
fmt.Printf("int64: %d -> int8: %d (注意溢出)\n", bigInt, smallInt)
// 字符串和数值之间的转换
var numStr string = "123"
var strNum int
// 字符串转数字
if val, err := strconv.Atoi(numStr); err == nil {
strNum = val
fmt.Printf("字符串'%s'转换为数字: %d\n", numStr, strNum)
}
// 数字转字符串
var num int = 456
var result string = strconv.Itoa(num)
fmt.Printf("数字%d转换为字符串: '%s'\n", num, result)
// 更复杂的字符串数值转换
floatStr := "3.14159"
if floatNum, err := strconv.ParseFloat(floatStr, 64); err == nil {
fmt.Printf("字符串'%s'转换为浮点数: %.5f\n", floatStr, floatNum)
}
// 布尔值转换
boolStr := "true"
if boolVal, err := strconv.ParseBool(boolStr); err == nil {
fmt.Printf("字符串'%s'转换为布尔值: %t\n", boolStr, boolVal)
}
}
2. 类型推断的智能性
go
package main
import "fmt"
func main() {
// 基本类型推断
var a = 42 // int
var b = 3.14 // float64
var c = "hello" // string
var d = true // bool
var e = 'A' // rune (int32)
fmt.Printf("a的类型: %T, 值: %v\n", a, a)
fmt.Printf("b的类型: %T, 值: %v\n", b, b)
fmt.Printf("c的类型: %T, 值: %v\n", c, c)
fmt.Printf("d的类型: %T, 值: %v\n", d, d)
fmt.Printf("e的类型: %T, 值: %v\n", e, e)
// 从表达式推断类型
x := 10
y := 20
sum := x + y // int
avg := float64(sum) / 2 // float64
fmt.Printf("sum的类型: %T, 值: %v\n", sum, sum)
fmt.Printf("avg的类型: %T, 值: %v\n", avg, avg)
// 从函数返回值推断类型
result := calculateArea(5.0, 3.0)
fmt.Printf("result的类型: %T, 值: %.2f\n", result, result)
// 复杂表达式的类型推断
complex1 := 1 + 2i // complex128
complex2 := complex64(1 + 2i) // complex64
fmt.Printf("complex1的类型: %T\n", complex1)
fmt.Printf("complex2的类型: %T\n", complex2)
}
func calculateArea(length, width float64) float64 {
return length * width
}
3. 类型断言和接口转换
go
package main
import "fmt"
func main() {
// 接口类型和类型断言
var i interface{} = "hello world"
// 类型断言(安全方式)
if str, ok := i.(string); ok {
fmt.Printf("成功断言为string: %s\n", str)
} else {
fmt.Println("断言失败")
}
// 类型断言(直接方式,可能panic)
str := i.(string)
fmt.Printf("直接断言: %s\n", str)
// 类型选择
checkType := func(x interface{}) {
switch v := x.(type) {
case int:
fmt.Printf("整数: %d\n", v)
case float64:
fmt.Printf("浮点数: %.2f\n", v)
case string:
fmt.Printf("字符串: %s\n", v)
case bool:
fmt.Printf("布尔值: %t\n", v)
default:
fmt.Printf("未知类型: %T\n", v)
}
}
checkType(42)
checkType(3.14)
checkType("Go语言")
checkType(true)
checkType([]int{1, 2, 3})
}
作用域和生命周期
1. 不同作用域的变量
go
package main
import "fmt"
// 包级别变量(全局变量)
var globalVar string = "我是全局变量"
var packageVar = "我是包变量"
func main() {
// 函数级别变量
var functionVar string = "我是函数变量"
localVar := "我是本地变量"
fmt.Println("=== 作用域演示 ===")
fmt.Println(globalVar)
fmt.Println(packageVar)
fmt.Println(functionVar)
fmt.Println(localVar)
// 块级作用域
if true {
blockVar := "我是块变量"
fmt.Println(blockVar)
// 可以访问外层变量
fmt.Println("在块内访问函数变量:", functionVar)
// 内层变量可以覆盖外层同名变量
localVar := "我是内层的localVar"
fmt.Println("内层localVar:", localVar)
}
// 块外无法访问块内变量
// fmt.Println(blockVar) // 编译错误
fmt.Println("外层localVar:", localVar) // 仍然是原值
// for循环的作用域
for i := 0; i < 3; i++ {
loopVar := fmt.Sprintf("循环变量_%d", i)
fmt.Println(loopVar)
}
// fmt.Println(i) // 编译错误,i超出作用域
// fmt.Println(loopVar) // 编译错误,loopVar超出作用域
demonstrateScope()
}
func demonstrateScope() {
fmt.Println("\n=== 函数作用域演示 ===")
// 可以访问全局变量
fmt.Println("在函数中访问全局变量:", globalVar)
// 局部变量覆盖全局变量
globalVar := "我是局部的globalVar"
fmt.Println("局部覆盖后:", globalVar)
// 嵌套函数的作用域
innerFunction := func() {
innerVar := "我是内部函数变量"
fmt.Println(innerVar)
fmt.Println("内部函数访问外层:", globalVar)
}
innerFunction()
}
2. 变量的生命周期
go
package main
import (
"fmt"
"runtime"
)
// 全局变量在程序启动时创建,程序结束时销毁
var globalCounter int = 0
func main() {
fmt.Println("=== 变量生命周期演示 ===")
// 局部变量在函数调用时创建,函数返回时销毁
localVar := "我是局部变量"
fmt.Println(localVar)
// 演示闭包中的变量生命周期
counter := createCounter()
fmt.Printf("第1次调用: %d\n", counter())
fmt.Printf("第2次调用: %d\n", counter())
fmt.Printf("第3次调用: %d\n", counter())
// 演示指针和内存分配
demonstrateMemoryAllocation()
// 强制垃圾回收
runtime.GC()
fmt.Println("执行垃圾回收")
}
// 闭包函数,返回的函数保持对局部变量的引用
func createCounter() func() int {
count := 0 // 这个变量的生命周期被延长了
return func() int {
count++
return count
}
}
func demonstrateMemoryAllocation() {
fmt.Println("\n=== 内存分配演示 ===")
// 栈分配的变量
stackVar := 42
fmt.Printf("栈变量地址: %p, 值: %d\n", &stackVar, stackVar)
// 堆分配的变量(通过new创建)
heapVar := new(int)
*heapVar = 100
fmt.Printf("堆变量地址: %p, 值: %d\n", heapVar, *heapVar)
// 切片会在堆上分配
slice := make([]int, 1000)
slice[0] = 999
fmt.Printf("切片首元素地址: %p, 值: %d\n", &slice[0], slice[0])
// 大数组可能在堆上分配
bigArray := [10000]int{1, 2, 3}
fmt.Printf("大数组首元素地址: %p, 值: %d\n", &bigArray[0], bigArray[0])
}
3. 变量遮蔽(Shadowing)
go
package main
import "fmt"
var x = "全局x"
func main() {
fmt.Println("=== 变量遮蔽演示 ===")
fmt.Printf("全局x: %s\n", x)
// 函数级别遮蔽全局变量
x := "函数x"
fmt.Printf("函数x: %s\n", x)
// 块级别遮蔽
{
x := "块x"
fmt.Printf("块x: %s\n", x)
// 更深层的遮蔽
{
x := "深层块x"
fmt.Printf("深层块x: %s\n", x)
}
fmt.Printf("回到块x: %s\n", x)
}
fmt.Printf("回到函数x: %s\n", x)
// 短变量声明的遮蔽陷阱
demonstrateShadowingTrap()
}
func demonstrateShadowingTrap() {
fmt.Println("\n=== 遮蔽陷阱演示 ===")
var err error
// 这里创建了一个新的err变量,遮蔽了外层的err
if data, err := getData(); err != nil {
fmt.Printf("内层err: %v\n", err)
}
// 外层的err仍然是nil
fmt.Printf("外层err: %v\n", err)
// 正确的做法
var data string
data, err = getData()
if err != nil {
fmt.Printf("正确方式的err: %v\n", err)
} else {
fmt.Printf("获取的数据: %s\n", data)
}
}
func getData() (string, error) {
return "hello", fmt.Errorf("模拟错误")
}
实战案例:构建一个简单的用户信息管理程序
让我们通过一个完整的案例来综合运用所学的知识:
go
package main
import (
"fmt"
"strconv"
"strings"
"time"
)
// 用户状态常量
const (
UserStatusInactive = iota
UserStatusActive
UserStatusSuspended
UserStatusDeleted
)
// 用户类型常量
const (
UserTypeRegular = iota + 1
UserTypeVIP
UserTypeAdmin
)
// 权限常量(使用位运算)
const (
PermissionRead = 1 << iota
PermissionWrite
PermissionDelete
PermissionAdmin
)
// 用户信息结构体(我们将在后续文章详细介绍结构体)
type User struct {
ID int
Username string
Email string
Age int
Balance float64
IsActive bool
UserType int
Permissions int
CreatedAt time.Time
}
func main() {
fmt.Println("=== 用户信息管理系统 ===")
// 创建用户数据
users := createSampleUsers()
// 显示所有用户信息
displayUsers(users)
// 用户状态管理
fmt.Println("\n=== 用户状态管理 ===")
manageUserStatus()
// 权限管理
fmt.Println("\n=== 权限管理 ===")
managePermissions()
// 数据类型转换演示
fmt.Println("\n=== 数据转换演示 ===")
demonstrateDataConversion()
}
func createSampleUsers() []User {
var users []User
// 用户1:普通用户
user1 := User{
ID: 1,
Username: "张三",
Email: "zhangsan@example.com",
Age: 25,
Balance: 1500.50,
IsActive: true,
UserType: UserTypeRegular,
Permissions: PermissionRead | PermissionWrite,
CreatedAt: time.Now().AddDate(0, -2, 0),
}
// 用户2:VIP用户
user2 := User{
ID: 2,
Username: "李四",
Email: "lisi@example.com",
Age: 30,
Balance: 5000.00,
IsActive: true,
UserType: UserTypeVIP,
Permissions: PermissionRead | PermissionWrite | PermissionDelete,
CreatedAt: time.Now().AddDate(0, -6, 0),
}
// 用户3:管理员
user3 := User{
ID: 3,
Username: "管理员",
Email: "admin@example.com",
Age: 35,
Balance: 0.00,
IsActive: true,
UserType: UserTypeAdmin,
Permissions: PermissionRead | PermissionWrite | PermissionDelete | PermissionAdmin,
CreatedAt: time.Now().AddDate(-1, 0, 0),
}
users = append(users, user1, user2, user3)
return users
}
func displayUsers(users []User) {
fmt.Println("\n当前用户列表:")
fmt.Println(strings.Repeat("-", 80))
fmt.Printf("%-3s %-10s %-20s %-3s %-10s %-8s %-10s %-10s\n",
"ID", "用户名", "邮箱", "年龄", "余额", "状态", "类型", "权限")
fmt.Println(strings.Repeat("-", 80))
for _, user := range users {
status := "激活"
if !user.IsActive {
status = "禁用"
}
userType := getUserTypeName(user.UserType)
permissions := getPermissionNames(user.Permissions)
fmt.Printf("%-3d %-10s %-20s %-3d %-10.2f %-8s %-10s %s\n",
user.ID, user.Username, user.Email, user.Age, user.Balance,
status, userType, permissions)
}
}
func getUserTypeName(userType int) string {
switch userType {
case UserTypeRegular:
return "普通用户"
case UserTypeVIP:
return "VIP用户"
case UserTypeAdmin:
return "管理员"
default:
return "未知"
}
}
func getPermissionNames(permissions int) string {
var perms []string
if permissions&PermissionRead != 0 {
perms = append(perms, "读")
}
if permissions&PermissionWrite != 0 {
perms = append(perms, "写")
}
if permissions&PermissionDelete != 0 {
perms = append(perms, "删")
}
if permissions&PermissionAdmin != 0 {
perms = append(perms, "管理")
}
return strings.Join(perms, ",")
}
func manageUserStatus() {
currentStatus := UserStatusActive
fmt.Printf("当前用户状态: %s\n", getStatusName(currentStatus))
// 状态转换
currentStatus = UserStatusSuspended
fmt.Printf("用户已被暂停: %s\n", getStatusName(currentStatus))
currentStatus = UserStatusActive
fmt.Printf("用户已恢复: %s\n", getStatusName(currentStatus))
}
func getStatusName(status int) string {
switch status {
case UserStatusInactive:
return "未激活"
case UserStatusActive:
return "已激活"
case UserStatusSuspended:
return "已暂停"
case UserStatusDeleted:
return "已删除"
default:
return "未知状态"
}
}
func managePermissions() {
// 基础权限
userPerms := PermissionRead
fmt.Printf("初始权限: %s\n", getPermissionNames(userPerms))
// 添加写权限
userPerms |= PermissionWrite
fmt.Printf("添加写权限后: %s\n", getPermissionNames(userPerms))
// 添加删除权限
userPerms |= PermissionDelete
fmt.Printf("添加删除权限后: %s\n", getPermissionNames(userPerms))
// 检查是否有特定权限
if userPerms&PermissionWrite != 0 {
fmt.Println("用户有写权限")
}
// 移除写权限
userPerms &^= PermissionWrite
fmt.Printf("移除写权限后: %s\n", getPermissionNames(userPerms))
}
func demonstrateDataConversion() {
// 字符串转数字
ageStr := "25"
if age, err := strconv.Atoi(ageStr); err == nil {
fmt.Printf("年龄字符串'%s'转换为数字: %d\n", ageStr, age)
}
// 浮点数转换
balanceStr := "1500.50"
if balance, err := strconv.ParseFloat(balanceStr, 64); err == nil {
fmt.Printf("余额字符串'%s'转换为浮点数: %.2f\n", balanceStr, balance)
}
// 布尔值转换
activeStr := "true"
if isActive, err := strconv.ParseBool(activeStr); err == nil {
fmt.Printf("状态字符串'%s'转换为布尔值: %t\n", activeStr, isActive)
}
// 数字转字符串
userID := 12345
userIDStr := strconv.Itoa(userID)
fmt.Printf("用户ID %d 转换为字符串: '%s'\n", userID, userIDStr)
// 格式化输出
price := 99.99
priceStr := fmt.Sprintf("%.2f", price)
fmt.Printf("价格 %.2f 格式化为字符串: '%s'\n", price, priceStr)
}
最佳实践与小贴士
1. 变量命名最佳实践
go
package main
import "fmt"
func main() {
// ✅ 好的命名
var userName string = "张三"
var userAge int = 25
var isUserActive bool = true
var maxRetryCount int = 3
// ❌ 不好的命名
var u string = "张三" // 太短,含义不明
var userAgeInYears int = 25 // 太冗长
var flag bool = true // 含义模糊
var MAX_RETRY_COUNT int = 3 // 不符合Go命名规范
// ✅ 常量命名(使用驼峰命名)
const MaxConnections = 100
const DefaultTimeout = 30
const APIVersion = "v1.0"
// ✅ 包级别变量可以使用简短名称
var (
cfg *Config // 配置
logger *Logger // 日志器
db *Database // 数据库
)
fmt.Printf("用户: %s, 年龄: %d, 激活: %t\n", userName, userAge, isUserActive)
}
// 假设的类型定义
type Config struct{}
type Logger struct{}
type Database struct{}
2. 类型选择指南
go
package main
import "fmt"
func main() {
// ✅ 整数类型选择指南
var counter int // 一般计数器使用int
var id int64 // ID通常使用int64
var age uint8 // 年龄可以使用uint8(0-255)
var fileSize int64 // 文件大小使用int64
// ✅ 浮点数类型选择
var price float64 // 金钱计算使用float64
var ratio float32 // 比率可以使用float32
// ✅ 字符串处理
var name string // 普通字符串
var description string = `这是一个多行字符串
可以包含换行符
和其他特殊字符`
// ✅ 布尔值使用
var isReady bool // 明确的布尔状态
var hasError bool // 错误标志
fmt.Printf("计数器: %d, ID: %d, 年龄: %d\n", counter, id, age)
fmt.Printf("价格: %.2f, 比率: %.2f\n", price, ratio)
fmt.Printf("姓名: %s\n", name)
fmt.Printf("描述: %s\n", description)
fmt.Printf("就绪: %t, 有错误: %t\n", isReady, hasError)
}
3. 错误处理模式
go
package main
import (
"fmt"
"strconv"
)
func main() {
// ✅ 标准错误处理模式
input := "123abc"
if num, err := strconv.Atoi(input); err != nil {
fmt.Printf("转换失败: %v\n", err)
} else {
fmt.Printf("转换成功: %d\n", num)
}
// ✅ 多返回值处理
result, err := divide(10, 0)
if err != nil {
fmt.Printf("计算错误: %v\n", err)
return
}
fmt.Printf("结果: %.2f\n", result)
// ✅ 类型断言的安全处理
var value interface{} = "hello"
if str, ok := value.(string); ok {
fmt.Printf("字符串值: %s\n", str)
} else {
fmt.Println("类型断言失败")
}
}
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("除数不能为零")
}
return a / b, nil
}
4. 性能优化小贴士
go
package main
import (
"fmt"
"strconv"
"strings"
)
func main() {
// ✅ 字符串拼接优化
var parts []string
for i := 0; i < 5; i++ {
parts = append(parts, "part"+strconv.Itoa(i))
}
result := strings.Join(parts, ",")
fmt.Printf("拼接结果: %s\n", result)
// ❌ 低效的字符串拼接
badResult := ""
for i := 0; i < 5; i++ {
badResult += "part" + strconv.Itoa(i) + ","
}
fmt.Printf("低效拼接: %s\n", badResult)
// ✅ 预分配切片容量
numbers := make([]int, 0, 100) // 预分配容量为100
for i := 0; i < 100; i++ {
numbers = append(numbers, i)
}
// ✅ 使用常量而不是重复计算
const Pi = 3.14159265359
radius := 5.0
area := Pi * radius * radius
fmt.Printf("圆面积: %.2f\n", area)
}
总结
通过本文的学习,我们深入了解了Go语言的基础语法,包括:
核心知识点回顾
- 变量声明 :掌握了
var
关键字和短变量声明:=
的使用方法 - 数据类型:熟悉了Go语言丰富的数据类型体系
- 常量和iota:学会了常量定义和iota枚举器的强大功能
- 类型转换:理解了显式类型转换和类型推断机制
- 作用域管理:掌握了变量的作用域和生命周期概念
实践要点
- 类型安全:Go语言是强类型语言,类型转换必须显式进行
- 零值初始化:未初始化的变量会被赋予类型的零值
- 作用域规则:理解不同层级的作用域,避免变量遮蔽陷阱
- 命名规范:遵循Go语言的命名约定,使用驼峰命名法
- 错误处理:养成良好的错误处理习惯
性能考虑
- 选择合适的数据类型以优化内存使用
- 注意类型转换的性能开销
- 合理使用常量减少重复计算
- 理解栈和堆分配的区别
下一步学习
在下一篇文章中,我们将学习Go语言的控制结构,包括条件语句、循环语句和分支语句。这些控制结构将让我们能够编写更复杂的程序逻辑。
技术评估
- 实用性: ⭐⭐⭐⭐⭐ (基础必备)
- 学习曲线: ⭐⭐ (相对简单)
- 性能表现: ⭐⭐⭐⭐⭐ (类型安全且高效)
- 开发效率: ⭐⭐⭐⭐ (语法简洁)
- 未来发展: ⭐⭐⭐⭐⭐ (Go语言核心基础)
欢迎关注我的技术博客,一起交流Go语言学习心得!在后续文章中,我们将继续深入学习Go语言的高级特性,包括函数、结构体、接口、并发编程等内容。如果你有任何问题或建议,欢迎在评论区留言讨论!
© 版权所有 | Go语言从入门到精通系列文章 本文为原创内容,未经作者明确授权,禁止任何形式的转载、复制或内容搬运。违者将依法追究法律责任。如需转载,请联系作者获得书面许可。