初始提交
This commit is contained in:
119
golang-learning/01-basics/01-hello-world.go
Normal file
119
golang-learning/01-basics/01-hello-world.go
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
01-hello-world.go - Go 语言入门第一课
|
||||
|
||||
学习目标:
|
||||
1. 了解 Go 程序的基本结构
|
||||
2. 理解包(package)的概念
|
||||
3. 学会使用 fmt 包进行输出
|
||||
4. 掌握 main 函数的作用
|
||||
|
||||
知识点:
|
||||
- package 声明
|
||||
- import 导入
|
||||
- main 函数
|
||||
- fmt.Println 输出函数
|
||||
*/
|
||||
|
||||
// 每个 Go 文件都必须以 package 声明开始
|
||||
// main 包是特殊的包,表示这是一个可执行程序
|
||||
package main
|
||||
|
||||
// import 用于导入其他包
|
||||
// fmt 包提供了格式化输入输出的功能
|
||||
import "fmt"
|
||||
|
||||
// main 函数是程序的入口点
|
||||
// 当运行程序时,会自动执行 main 函数
|
||||
func main() {
|
||||
// fmt.Println 用于输出文本并自动换行
|
||||
fmt.Println("Hello, World!")
|
||||
fmt.Println("欢迎来到 Go 语言的世界!")
|
||||
|
||||
// 你也可以使用 fmt.Print(不换行)或 fmt.Printf(格式化输出)
|
||||
fmt.Print("这是 ")
|
||||
fmt.Print("同一行的输出\n") // \n 表示换行
|
||||
|
||||
// fmt.Printf 支持格式化输出,类似于 C 语言的 printf
|
||||
name := "Go"
|
||||
version := 1.21
|
||||
fmt.Printf("我正在学习 %s 语言,版本是 %.2f\n", name, version)
|
||||
|
||||
// 多种输出方式的演示
|
||||
demonstrateOutput()
|
||||
}
|
||||
|
||||
// demonstrateOutput 演示不同的输出方式
|
||||
func demonstrateOutput() {
|
||||
fmt.Println("\n=== 输出方式演示 ===")
|
||||
|
||||
// 1. 基本输出
|
||||
fmt.Println("1. fmt.Println - 输出并换行")
|
||||
|
||||
// 2. 不换行输出
|
||||
fmt.Print("2. fmt.Print - ")
|
||||
fmt.Print("不换行输出")
|
||||
fmt.Print("\n") // 手动换行
|
||||
|
||||
// 3. 格式化输出
|
||||
age := 25
|
||||
height := 175.5
|
||||
isStudent := true
|
||||
|
||||
fmt.Printf("3. fmt.Printf - 格式化输出:\n")
|
||||
fmt.Printf(" 年龄: %d 岁\n", age) // %d 表示整数
|
||||
fmt.Printf(" 身高: %.1f cm\n", height) // %.1f 表示保留1位小数的浮点数
|
||||
fmt.Printf(" 是学生: %t\n", isStudent) // %t 表示布尔值
|
||||
fmt.Printf(" 十六进制年龄: %x\n", age) // %x 表示十六进制
|
||||
fmt.Printf(" 八进制年龄: %o\n", age) // %o 表示八进制
|
||||
|
||||
// 4. 通用格式符 %v
|
||||
fmt.Printf("4. 通用格式符 %%v:\n")
|
||||
fmt.Printf(" 年龄: %v, 身高: %v, 是学生: %v\n", age, height, isStudent)
|
||||
|
||||
// 5. 详细格式符 %+v 和 %#v(主要用于结构体)
|
||||
person := struct {
|
||||
Name string
|
||||
Age int
|
||||
}{"张三", 30}
|
||||
|
||||
fmt.Printf("5. 结构体输出:\n")
|
||||
fmt.Printf(" %%v: %v\n", person) // 简单格式
|
||||
fmt.Printf(" %%+v: %+v\n", person) // 包含字段名
|
||||
fmt.Printf(" %%#v: %#v\n", person) // Go 语法格式
|
||||
}
|
||||
|
||||
/*
|
||||
运行这个程序:
|
||||
1. 在终端中进入 01-basics 目录
|
||||
2. 执行命令:go run 01-hello-world.go
|
||||
|
||||
预期输出:
|
||||
Hello, World!
|
||||
欢迎来到 Go 语言的世界!
|
||||
这是 同一行的输出
|
||||
我正在学习 Go 语言,版本是 1.21
|
||||
|
||||
=== 输出方式演示 ===
|
||||
1. fmt.Println - 输出并换行
|
||||
2. fmt.Print - 不换行输出
|
||||
3. fmt.Printf - 格式化输出:
|
||||
年龄: 25 岁
|
||||
身高: 175.5 cm
|
||||
是学生: true
|
||||
十六进制年龄: 19
|
||||
八进制年龄: 31
|
||||
4. 通用格式符 %v:
|
||||
年龄: 25, 身高: 175.5, 是学生: true
|
||||
5. 结构体输出:
|
||||
%v: {张三 30}
|
||||
%+v: {Name:张三 Age:30}
|
||||
%#v: struct { Name string; Age int }{Name:"张三", Age:30}
|
||||
|
||||
学习要点:
|
||||
1. Go 程序必须有 package 声明
|
||||
2. main 包表示可执行程序
|
||||
3. main 函数是程序入口
|
||||
4. 使用 import 导入需要的包
|
||||
5. fmt 包提供了丰富的输出功能
|
||||
6. 注释使用 // 或
|
||||
*/
|
258
golang-learning/01-basics/02-variables.go
Normal file
258
golang-learning/01-basics/02-variables.go
Normal file
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
02-variables.go - Go 语言变量详解
|
||||
|
||||
学习目标:
|
||||
1. 掌握变量声明的多种方式
|
||||
2. 理解 Go 的类型推断
|
||||
3. 学会使用短变量声明
|
||||
4. 了解变量的作用域
|
||||
5. 掌握零值的概念
|
||||
|
||||
知识点:
|
||||
- var 关键字声明
|
||||
- 短变量声明 :=
|
||||
- 类型推断
|
||||
- 零值
|
||||
- 变量作用域
|
||||
- 多变量声明
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
// 包级别变量声明(全局变量)
|
||||
var globalVar = "我是全局变量"
|
||||
var (
|
||||
// 使用括号可以声明多个变量
|
||||
packageVar1 = "包变量1"
|
||||
packageVar2 = "包变量2"
|
||||
packageVar3 int = 100
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== Go 语言变量详解 ===\n")
|
||||
|
||||
// 演示各种变量声明方式
|
||||
demonstrateVariableDeclaration()
|
||||
|
||||
// 演示零值
|
||||
demonstrateZeroValues()
|
||||
|
||||
// 演示类型推断
|
||||
demonstrateTypeInference()
|
||||
|
||||
// 演示多变量声明
|
||||
demonstrateMultipleDeclaration()
|
||||
|
||||
// 演示变量作用域
|
||||
demonstrateScope()
|
||||
|
||||
// 演示变量赋值和修改
|
||||
demonstrateAssignment()
|
||||
}
|
||||
|
||||
// demonstrateVariableDeclaration 演示变量声明的不同方式
|
||||
func demonstrateVariableDeclaration() {
|
||||
fmt.Println("1. 变量声明方式:")
|
||||
|
||||
// 方式1: var 关键字 + 类型声明
|
||||
var name string
|
||||
name = "张三"
|
||||
fmt.Printf(" 方式1 - var name string: %s\n", name)
|
||||
|
||||
// 方式2: var 关键字 + 类型声明 + 初始化
|
||||
var age int = 25
|
||||
fmt.Printf(" 方式2 - var age int = 25: %d\n", age)
|
||||
|
||||
// 方式3: var 关键字 + 类型推断
|
||||
var city = "北京" // Go 会自动推断为 string 类型
|
||||
fmt.Printf(" 方式3 - var city = \"北京\": %s\n", city)
|
||||
|
||||
// 方式4: 短变量声明(最常用)
|
||||
height := 175.5 // 自动推断为 float64 类型
|
||||
fmt.Printf(" 方式4 - height := 175.5: %.1f\n", height)
|
||||
|
||||
// 注意:短变量声明只能在函数内部使用
|
||||
// 在包级别必须使用 var 关键字
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateZeroValues 演示 Go 的零值概念
|
||||
func demonstrateZeroValues() {
|
||||
fmt.Println("2. 零值演示:")
|
||||
fmt.Println(" Go 中每种类型都有默认的零值")
|
||||
|
||||
// 声明变量但不初始化,会自动赋予零值
|
||||
var intVar int
|
||||
var floatVar float64
|
||||
var boolVar bool
|
||||
var stringVar string
|
||||
var pointerVar *int
|
||||
|
||||
fmt.Printf(" int 零值: %d\n", intVar) // 0
|
||||
fmt.Printf(" float64 零值: %f\n", floatVar) // 0.000000
|
||||
fmt.Printf(" bool 零值: %t\n", boolVar) // false
|
||||
fmt.Printf(" string 零值: '%s'\n", stringVar) // ""(空字符串)
|
||||
fmt.Printf(" pointer 零值: %v\n", pointerVar) // <nil>
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateTypeInference 演示类型推断
|
||||
func demonstrateTypeInference() {
|
||||
fmt.Println("3. 类型推断演示:")
|
||||
|
||||
// Go 可以根据赋值自动推断类型
|
||||
var a = 42 // 推断为 int
|
||||
var b = 3.14 // 推断为 float64
|
||||
var c = "Hello" // 推断为 string
|
||||
var d = true // 推断为 bool
|
||||
|
||||
// 使用 %T 可以打印变量的类型
|
||||
fmt.Printf(" a = %v, 类型: %T\n", a, a)
|
||||
fmt.Printf(" b = %v, 类型: %T\n", b, b)
|
||||
fmt.Printf(" c = %v, 类型: %T\n", c, c)
|
||||
fmt.Printf(" d = %v, 类型: %T\n", d, d)
|
||||
|
||||
// 短变量声明也支持类型推断
|
||||
x := 100 // int
|
||||
y := 2.5 // float64
|
||||
z := 'A' // rune (int32)
|
||||
|
||||
fmt.Printf(" x := 100, 类型: %T\n", x)
|
||||
fmt.Printf(" y := 2.5, 类型: %T\n", y)
|
||||
fmt.Printf(" z := 'A', 类型: %T, 值: %d\n", z, z)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateMultipleDeclaration 演示多变量声明
|
||||
func demonstrateMultipleDeclaration() {
|
||||
fmt.Println("4. 多变量声明:")
|
||||
|
||||
// 方式1: 同时声明多个相同类型的变量
|
||||
var x, y, z int = 1, 2, 3
|
||||
fmt.Printf(" var x, y, z int = 1, 2, 3: %d, %d, %d\n", x, y, z)
|
||||
|
||||
// 方式2: 同时声明多个不同类型的变量
|
||||
var name, age, height = "李四", 30, 180.0
|
||||
fmt.Printf(" var name, age, height = ...: %s, %d, %.1f\n", name, age, height)
|
||||
|
||||
// 方式3: 使用短变量声明
|
||||
a, b, c := "Go", 1.21, true
|
||||
fmt.Printf(" a, b, c := ...: %s, %.2f, %t\n", a, b, c)
|
||||
|
||||
// 方式4: 使用括号组织多个变量声明
|
||||
var (
|
||||
firstName = "王"
|
||||
lastName = "五"
|
||||
fullName = firstName + lastName
|
||||
)
|
||||
fmt.Printf(" 组合声明: %s\n", fullName)
|
||||
|
||||
// 变量交换(Go 的特色功能)
|
||||
m, n := 10, 20
|
||||
fmt.Printf(" 交换前: m=%d, n=%d\n", m, n)
|
||||
m, n = n, m // 交换变量值
|
||||
fmt.Printf(" 交换后: m=%d, n=%d\n", m, n)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateScope 演示变量作用域
|
||||
func demonstrateScope() {
|
||||
fmt.Println("5. 变量作用域:")
|
||||
|
||||
// 访问全局变量
|
||||
fmt.Printf(" 全局变量: %s\n", globalVar)
|
||||
fmt.Printf(" 包变量: %s, %s, %d\n", packageVar1, packageVar2, packageVar3)
|
||||
|
||||
// 函数级别变量
|
||||
funcVar := "函数变量"
|
||||
fmt.Printf(" 函数变量: %s\n", funcVar)
|
||||
|
||||
// 块级别作用域
|
||||
if true {
|
||||
blockVar := "块变量"
|
||||
fmt.Printf(" 块变量(在 if 块内): %s\n", blockVar)
|
||||
|
||||
// 可以访问外层变量
|
||||
fmt.Printf(" 在块内访问函数变量: %s\n", funcVar)
|
||||
}
|
||||
|
||||
// blockVar 在这里无法访问,会编译错误
|
||||
// fmt.Println(blockVar) // 这行会报错
|
||||
|
||||
// for 循环的作用域
|
||||
for i := 0; i < 3; i++ {
|
||||
loopVar := fmt.Sprintf("循环变量_%d", i)
|
||||
fmt.Printf(" %s\n", loopVar)
|
||||
}
|
||||
// i 和 loopVar 在这里都无法访问
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateAssignment 演示变量赋值和修改
|
||||
func demonstrateAssignment() {
|
||||
fmt.Println("6. 变量赋值和修改:")
|
||||
|
||||
// 基本赋值
|
||||
var score int = 85
|
||||
fmt.Printf(" 初始分数: %d\n", score)
|
||||
|
||||
// 修改变量值
|
||||
score = 90
|
||||
fmt.Printf(" 修改后分数: %d\n", score)
|
||||
|
||||
// 复合赋值运算符
|
||||
score += 5 // 等同于 score = score + 5
|
||||
fmt.Printf(" score += 5: %d\n", score)
|
||||
|
||||
score -= 3 // 等同于 score = score - 3
|
||||
fmt.Printf(" score -= 3: %d\n", score)
|
||||
|
||||
score *= 2 // 等同于 score = score * 2
|
||||
fmt.Printf(" score *= 2: %d\n", score)
|
||||
|
||||
score /= 4 // 等同于 score = score / 4
|
||||
fmt.Printf(" score /= 4: %d\n", score)
|
||||
|
||||
score %= 10 // 等同于 score = score % 10
|
||||
fmt.Printf(" score %%= 10: %d\n", score)
|
||||
|
||||
// 自增和自减运算符
|
||||
fmt.Printf(" score++ 前: %d\n", score)
|
||||
score++ // 等同于 score = score + 1
|
||||
fmt.Printf(" score++ 后: %d\n", score)
|
||||
|
||||
score-- // 等同于 score = score - 1
|
||||
fmt.Printf(" score-- 后: %d\n", score)
|
||||
|
||||
// 注意:Go 中的 ++ 和 -- 是语句,不是表达式
|
||||
// 不能写成 x = score++ 这样的形式
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
/*
|
||||
运行这个程序:
|
||||
go run 02-variables.go
|
||||
|
||||
学习要点:
|
||||
1. Go 有多种变量声明方式,短变量声明 := 最常用
|
||||
2. Go 支持类型推断,可以自动确定变量类型
|
||||
3. 每种类型都有零值,未初始化的变量会自动赋予零值
|
||||
4. 变量有作用域限制,块内变量无法在块外访问
|
||||
5. Go 支持多变量同时声明和赋值
|
||||
6. 复合赋值运算符可以简化代码
|
||||
7. ++ 和 -- 在 Go 中是语句,不是表达式
|
||||
|
||||
常见错误:
|
||||
1. 在包级别使用短变量声明 := (只能在函数内使用)
|
||||
2. 访问超出作用域的变量
|
||||
3. 将 ++ 或 -- 当作表达式使用
|
||||
4. 忘记变量的零值概念
|
||||
*/
|
302
golang-learning/01-basics/03-constants.go
Normal file
302
golang-learning/01-basics/03-constants.go
Normal file
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
03-constants.go - Go 语言常量详解
|
||||
|
||||
学习目标:
|
||||
1. 理解常量的概念和作用
|
||||
2. 掌握常量声明的方式
|
||||
3. 学会使用 iota 枚举器
|
||||
4. 了解类型化和无类型化常量
|
||||
5. 掌握常量表达式的计算
|
||||
|
||||
知识点:
|
||||
- const 关键字
|
||||
- 常量组声明
|
||||
- iota 枚举器
|
||||
- 类型化常量 vs 无类型化常量
|
||||
- 常量表达式
|
||||
- 预定义常量
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
// 包级别常量声明
|
||||
const PI = 3.14159
|
||||
const COMPANY_NAME = "Go 学习公司"
|
||||
|
||||
// 常量组声明
|
||||
const (
|
||||
// 基本常量
|
||||
MAX_SIZE = 100
|
||||
MIN_SIZE = 1
|
||||
|
||||
// 使用表达式的常量
|
||||
BUFFER_SIZE = MAX_SIZE * 2
|
||||
|
||||
// 字符串常量
|
||||
VERSION = "1.0.0"
|
||||
AUTHOR = "Go 学习者"
|
||||
)
|
||||
|
||||
// 使用 iota 的枚举常量
|
||||
const (
|
||||
// iota 从 0 开始,每行递增 1
|
||||
MONDAY = iota // 0
|
||||
TUESDAY // 1
|
||||
WEDNESDAY // 2
|
||||
THURSDAY // 3
|
||||
FRIDAY // 4
|
||||
SATURDAY // 5
|
||||
SUNDAY // 6
|
||||
)
|
||||
|
||||
// 更复杂的 iota 用法
|
||||
const (
|
||||
_ = iota // 0,使用 _ 忽略第一个值
|
||||
KB = 1 << (10 * iota) // 1 << (10 * 1) = 1024
|
||||
MB // 1 << (10 * 2) = 1048576
|
||||
GB // 1 << (10 * 3) = 1073741824
|
||||
TB // 1 << (10 * 4) = 1099511627776
|
||||
)
|
||||
|
||||
// 类型化常量
|
||||
const (
|
||||
MAX_INT int = 2147483647
|
||||
MAX_FLOAT float64 = 1.7976931348623157e+308
|
||||
IS_ENABLED bool = true
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== Go 语言常量详解 ===\n")
|
||||
|
||||
// 演示基本常量使用
|
||||
demonstrateBasicConstants()
|
||||
|
||||
// 演示 iota 枚举器
|
||||
demonstrateIota()
|
||||
|
||||
// 演示常量表达式
|
||||
demonstrateConstantExpressions()
|
||||
|
||||
// 演示类型化和无类型化常量
|
||||
demonstrateTypedConstants()
|
||||
|
||||
// 演示常量的特性
|
||||
demonstrateConstantProperties()
|
||||
}
|
||||
|
||||
// demonstrateBasicConstants 演示基本常量使用
|
||||
func demonstrateBasicConstants() {
|
||||
fmt.Println("1. 基本常量使用:")
|
||||
|
||||
// 使用包级别常量
|
||||
fmt.Printf(" 圆周率: %f\n", PI)
|
||||
fmt.Printf(" 公司名称: %s\n", COMPANY_NAME)
|
||||
fmt.Printf(" 最大尺寸: %d\n", MAX_SIZE)
|
||||
fmt.Printf(" 缓冲区大小: %d\n", BUFFER_SIZE)
|
||||
|
||||
// 函数内部常量声明
|
||||
const LOCAL_CONST = "这是局部常量"
|
||||
fmt.Printf(" 局部常量: %s\n", LOCAL_CONST)
|
||||
|
||||
// 常量组声明(函数内部)
|
||||
const (
|
||||
RED = "红色"
|
||||
GREEN = "绿色"
|
||||
BLUE = "蓝色"
|
||||
)
|
||||
|
||||
fmt.Printf(" 颜色常量: %s, %s, %s\n", RED, GREEN, BLUE)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateIota 演示 iota 枚举器
|
||||
func demonstrateIota() {
|
||||
fmt.Println("2. iota 枚举器:")
|
||||
|
||||
// 基本 iota 用法
|
||||
fmt.Printf(" 星期枚举:\n")
|
||||
fmt.Printf(" MONDAY: %d\n", MONDAY)
|
||||
fmt.Printf(" TUESDAY: %d\n", TUESDAY)
|
||||
fmt.Printf(" WEDNESDAY: %d\n", WEDNESDAY)
|
||||
fmt.Printf(" THURSDAY: %d\n", THURSDAY)
|
||||
fmt.Printf(" FRIDAY: %d\n", FRIDAY)
|
||||
fmt.Printf(" SATURDAY: %d\n", SATURDAY)
|
||||
fmt.Printf(" SUNDAY: %d\n", SUNDAY)
|
||||
|
||||
// 存储单位枚举
|
||||
fmt.Printf(" 存储单位:\n")
|
||||
fmt.Printf(" KB: %d 字节\n", KB)
|
||||
fmt.Printf(" MB: %d 字节\n", MB)
|
||||
fmt.Printf(" GB: %d 字节\n", GB)
|
||||
fmt.Printf(" TB: %d 字节\n", TB)
|
||||
|
||||
// 更多 iota 示例
|
||||
const (
|
||||
A = iota * 2 // 0 * 2 = 0
|
||||
B // 1 * 2 = 2
|
||||
C // 2 * 2 = 4
|
||||
D // 3 * 2 = 6
|
||||
)
|
||||
|
||||
fmt.Printf(" iota 表达式: A=%d, B=%d, C=%d, D=%d\n", A, B, C, D)
|
||||
|
||||
// 跳过某些值
|
||||
const (
|
||||
E = iota + 1 // 0 + 1 = 1
|
||||
F // 1 + 1 = 2
|
||||
_ // 2 + 1 = 3 (跳过)
|
||||
G // 3 + 1 = 4
|
||||
)
|
||||
|
||||
fmt.Printf(" 跳过值: E=%d, F=%d, G=%d\n", E, F, G)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateConstantExpressions 演示常量表达式
|
||||
func demonstrateConstantExpressions() {
|
||||
fmt.Println("3. 常量表达式:")
|
||||
|
||||
// 算术表达式
|
||||
const (
|
||||
A = 10
|
||||
B = 20
|
||||
SUM = A + B
|
||||
PRODUCT = A * B
|
||||
QUOTIENT = B / A
|
||||
)
|
||||
|
||||
fmt.Printf(" 算术表达式:\n")
|
||||
fmt.Printf(" A + B = %d\n", SUM)
|
||||
fmt.Printf(" A * B = %d\n", PRODUCT)
|
||||
fmt.Printf(" B / A = %d\n", QUOTIENT)
|
||||
|
||||
// 字符串表达式
|
||||
const (
|
||||
FIRST_NAME = "张"
|
||||
LAST_NAME = "三"
|
||||
FULL_NAME = FIRST_NAME + LAST_NAME
|
||||
)
|
||||
|
||||
fmt.Printf(" 字符串表达式: %s\n", FULL_NAME)
|
||||
|
||||
// 布尔表达式
|
||||
const (
|
||||
X = 5
|
||||
Y = 10
|
||||
IS_GREATER = X > Y
|
||||
IS_EQUAL = X == Y
|
||||
)
|
||||
|
||||
fmt.Printf(" 布尔表达式:\n")
|
||||
fmt.Printf(" %d > %d = %t\n", X, Y, IS_GREATER)
|
||||
fmt.Printf(" %d == %d = %t\n", X, Y, IS_EQUAL)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateTypedConstants 演示类型化和无类型化常量
|
||||
func demonstrateTypedConstants() {
|
||||
fmt.Println("4. 类型化和无类型化常量:")
|
||||
|
||||
// 无类型化常量(更灵活)
|
||||
const UNTYPED_INT = 42
|
||||
const UNTYPED_FLOAT = 3.14
|
||||
const UNTYPED_STRING = "Hello"
|
||||
|
||||
// 类型化常量(类型固定)
|
||||
const TYPED_INT int = 42
|
||||
const TYPED_FLOAT float64 = 3.14
|
||||
const TYPED_STRING string = "Hello"
|
||||
|
||||
fmt.Printf(" 无类型化常量:\n")
|
||||
fmt.Printf(" UNTYPED_INT 可以赋值给不同的数值类型\n")
|
||||
|
||||
var i8 int8 = UNTYPED_INT // 可以
|
||||
var i16 int16 = UNTYPED_INT // 可以
|
||||
var i32 int32 = UNTYPED_INT // 可以
|
||||
var i64 int64 = UNTYPED_INT // 可以
|
||||
|
||||
fmt.Printf(" int8: %d, int16: %d, int32: %d, int64: %d\n", i8, i16, i32, i64)
|
||||
|
||||
fmt.Printf(" 类型化常量:\n")
|
||||
fmt.Printf(" TYPED_INT 只能赋值给相同类型\n")
|
||||
|
||||
var typedVar int = TYPED_INT // 可以,类型匹配
|
||||
// var typedVar2 int32 = TYPED_INT // 编译错误,类型不匹配
|
||||
|
||||
fmt.Printf(" typedVar: %d\n", typedVar)
|
||||
|
||||
// 演示无类型化常量的精度
|
||||
const HUGE = 1e1000 // 无类型化常量可以有很高的精度
|
||||
fmt.Printf(" 高精度常量: 可以定义超出普通类型范围的常量\n")
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateConstantProperties 演示常量的特性
|
||||
func demonstrateConstantProperties() {
|
||||
fmt.Println("5. 常量的特性:")
|
||||
|
||||
// 常量在编译时确定
|
||||
const COMPILE_TIME = 100 + 200
|
||||
fmt.Printf(" 编译时计算: %d\n", COMPILE_TIME)
|
||||
|
||||
// 常量不能修改
|
||||
const IMMUTABLE = "不可变"
|
||||
fmt.Printf(" 不可变性: %s\n", IMMUTABLE)
|
||||
// IMMUTABLE = "尝试修改" // 编译错误
|
||||
|
||||
// 常量可以用于数组长度
|
||||
const ARRAY_SIZE = 5
|
||||
var arr [ARRAY_SIZE]int
|
||||
fmt.Printf(" 用作数组长度: 数组长度为 %d\n", len(arr))
|
||||
|
||||
// 预定义常量
|
||||
fmt.Printf(" 预定义常量:\n")
|
||||
fmt.Printf(" true: %t\n", true)
|
||||
fmt.Printf(" false: %t\n", false)
|
||||
|
||||
// 常量的作用域
|
||||
fmt.Printf(" 常量作用域:\n")
|
||||
fmt.Printf(" 包级别常量在整个包中可见\n")
|
||||
fmt.Printf(" 函数级别常量只在函数内可见\n")
|
||||
|
||||
// 在块作用域中定义常量
|
||||
if true {
|
||||
const BLOCK_CONST = "块常量"
|
||||
fmt.Printf(" 块常量: %s\n", BLOCK_CONST)
|
||||
}
|
||||
// BLOCK_CONST 在这里不可访问
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
/*
|
||||
运行这个程序:
|
||||
go run 03-constants.go
|
||||
|
||||
学习要点:
|
||||
1. 常量使用 const 关键字声明,一旦定义不能修改
|
||||
2. 常量在编译时确定值,不能使用运行时才能确定的值
|
||||
3. iota 是常量生成器,在 const 块中从 0 开始递增
|
||||
4. 无类型化常量比类型化常量更灵活,可以赋值给兼容的类型
|
||||
5. 常量可以用于需要编译时常量的地方,如数组长度
|
||||
6. 常量表达式在编译时计算,支持算术、字符串、布尔运算
|
||||
7. 常量有作用域限制,和变量类似
|
||||
|
||||
常见用途:
|
||||
1. 定义配置参数(如缓冲区大小、超时时间)
|
||||
2. 定义枚举值(如状态码、错误码)
|
||||
3. 定义数学常数(如 PI、E)
|
||||
4. 定义字符串常量(如版本号、默认值)
|
||||
|
||||
注意事项:
|
||||
1. 常量值必须在编译时确定
|
||||
2. 不能将函数调用结果赋值给常量
|
||||
3. 不能将变量赋值给常量
|
||||
4. iota 只在 const 块中有效
|
||||
*/
|
414
golang-learning/01-basics/04-data-types.go
Normal file
414
golang-learning/01-basics/04-data-types.go
Normal file
@@ -0,0 +1,414 @@
|
||||
/*
|
||||
04-data-types.go - Go 语言数据类型详解
|
||||
|
||||
学习目标:
|
||||
1. 掌握 Go 的基本数据类型
|
||||
2. 理解不同数值类型的范围和用途
|
||||
3. 学会字符串和字符的处理
|
||||
4. 了解类型转换的方法
|
||||
5. 掌握复合数据类型的基础
|
||||
|
||||
知识点:
|
||||
- 整数类型 (int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64)
|
||||
- 浮点类型 (float32, float64)
|
||||
- 复数类型 (complex64, complex128)
|
||||
- 布尔类型 (bool)
|
||||
- 字符串类型 (string)
|
||||
- 字符类型 (byte, rune)
|
||||
- 类型转换
|
||||
- 类型别名
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== Go 语言数据类型详解 ===\n")
|
||||
|
||||
// 演示整数类型
|
||||
demonstrateIntegerTypes()
|
||||
|
||||
// 演示浮点类型
|
||||
demonstrateFloatTypes()
|
||||
|
||||
// 演示复数类型
|
||||
demonstrateComplexTypes()
|
||||
|
||||
// 演示布尔类型
|
||||
demonstrateBooleanType()
|
||||
|
||||
// 演示字符串类型
|
||||
demonstrateStringType()
|
||||
|
||||
// 演示字符类型
|
||||
demonstrateCharacterTypes()
|
||||
|
||||
// 演示类型转换
|
||||
demonstrateTypeConversion()
|
||||
|
||||
// 演示类型信息
|
||||
demonstrateTypeInfo()
|
||||
}
|
||||
|
||||
// demonstrateIntegerTypes 演示整数类型
|
||||
func demonstrateIntegerTypes() {
|
||||
fmt.Println("1. 整数类型:")
|
||||
|
||||
// 有符号整数
|
||||
var i8 int8 = 127 // -128 到 127
|
||||
var i16 int16 = 32767 // -32768 到 32767
|
||||
var i32 int32 = 2147483647 // -2^31 到 2^31-1
|
||||
var i64 int64 = 9223372036854775807 // -2^63 到 2^63-1
|
||||
|
||||
fmt.Printf(" 有符号整数:\n")
|
||||
fmt.Printf(" int8: %d (大小: %d 字节)\n", i8, unsafe.Sizeof(i8))
|
||||
fmt.Printf(" int16: %d (大小: %d 字节)\n", i16, unsafe.Sizeof(i16))
|
||||
fmt.Printf(" int32: %d (大小: %d 字节)\n", i32, unsafe.Sizeof(i32))
|
||||
fmt.Printf(" int64: %d (大小: %d 字节)\n", i64, unsafe.Sizeof(i64))
|
||||
|
||||
// 无符号整数
|
||||
var ui8 uint8 = 255 // 0 到 255
|
||||
var ui16 uint16 = 65535 // 0 到 65535
|
||||
var ui32 uint32 = 4294967295 // 0 到 2^32-1
|
||||
var ui64 uint64 = 18446744073709551615 // 0 到 2^64-1
|
||||
|
||||
fmt.Printf(" 无符号整数:\n")
|
||||
fmt.Printf(" uint8: %d (大小: %d 字节)\n", ui8, unsafe.Sizeof(ui8))
|
||||
fmt.Printf(" uint16: %d (大小: %d 字节)\n", ui16, unsafe.Sizeof(ui16))
|
||||
fmt.Printf(" uint32: %d (大小: %d 字节)\n", ui32, unsafe.Sizeof(ui32))
|
||||
fmt.Printf(" uint64: %d (大小: %d 字节)\n", ui64, unsafe.Sizeof(ui64))
|
||||
|
||||
// 平台相关的整数类型
|
||||
var i int = 2147483647 // 32位系统上是int32,64位系统上是int64
|
||||
var ui uint = 4294967295 // 32位系统上是uint32,64位系统上是uint64
|
||||
var uiptr uintptr = 0x12345678 // 存储指针的整数类型
|
||||
|
||||
fmt.Printf(" 平台相关类型:\n")
|
||||
fmt.Printf(" int: %d (大小: %d 字节)\n", i, unsafe.Sizeof(i))
|
||||
fmt.Printf(" uint: %d (大小: %d 字节)\n", ui, unsafe.Sizeof(ui))
|
||||
fmt.Printf(" uintptr: 0x%x (大小: %d 字节)\n", uiptr, unsafe.Sizeof(uiptr))
|
||||
|
||||
// 整数的不同表示法
|
||||
fmt.Printf(" 整数的不同表示法:\n")
|
||||
decimal := 42 // 十进制
|
||||
binary := 0b101010 // 二进制 (Go 1.13+)
|
||||
octal := 0o52 // 八进制 (Go 1.13+)
|
||||
hexadecimal := 0x2A // 十六进制
|
||||
|
||||
fmt.Printf(" 十进制: %d\n", decimal)
|
||||
fmt.Printf(" 二进制: %d (0b%b)\n", binary, binary)
|
||||
fmt.Printf(" 八进制: %d (0o%o)\n", octal, octal)
|
||||
fmt.Printf(" 十六进制: %d (0x%X)\n", hexadecimal, hexadecimal)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateFloatTypes 演示浮点类型
|
||||
func demonstrateFloatTypes() {
|
||||
fmt.Println("2. 浮点类型:")
|
||||
|
||||
// float32 和 float64
|
||||
var f32 float32 = 3.14159
|
||||
var f64 float64 = 3.141592653589793
|
||||
|
||||
fmt.Printf(" 基本浮点类型:\n")
|
||||
fmt.Printf(" float32: %.7f (大小: %d 字节)\n", f32, unsafe.Sizeof(f32))
|
||||
fmt.Printf(" float64: %.15f (大小: %d 字节)\n", f64, unsafe.Sizeof(f64))
|
||||
|
||||
// 浮点数的特殊值
|
||||
fmt.Printf(" 特殊浮点值:\n")
|
||||
fmt.Printf(" 正无穷: %f\n", math.Inf(1))
|
||||
fmt.Printf(" 负无穷: %f\n", math.Inf(-1))
|
||||
fmt.Printf(" NaN: %f\n", math.NaN())
|
||||
|
||||
// 浮点数的科学计数法
|
||||
scientific1 := 1.23e4 // 1.23 * 10^4 = 12300
|
||||
scientific2 := 1.23e-4 // 1.23 * 10^-4 = 0.000123
|
||||
|
||||
fmt.Printf(" 科学计数法:\n")
|
||||
fmt.Printf(" 1.23e4 = %f\n", scientific1)
|
||||
fmt.Printf(" 1.23e-4 = %f\n", scientific2)
|
||||
|
||||
// 浮点数精度问题
|
||||
fmt.Printf(" 精度问题演示:\n")
|
||||
var a float64 = 0.1
|
||||
var b float64 = 0.2
|
||||
var c float64 = 0.3
|
||||
fmt.Printf(" 0.1 + 0.2 = %.17f\n", a+b)
|
||||
fmt.Printf(" 0.3 = %.17f\n", c)
|
||||
fmt.Printf(" 0.1 + 0.2 == 0.3: %t\n", a+b == c)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateComplexTypes 演示复数类型
|
||||
func demonstrateComplexTypes() {
|
||||
fmt.Println("3. 复数类型:")
|
||||
|
||||
// complex64 和 complex128
|
||||
var c64 complex64 = 3 + 4i
|
||||
var c128 complex128 = 5 + 6i
|
||||
|
||||
fmt.Printf(" 基本复数类型:\n")
|
||||
fmt.Printf(" complex64: %v (大小: %d 字节)\n", c64, unsafe.Sizeof(c64))
|
||||
fmt.Printf(" complex128: %v (大小: %d 字节)\n", c128, unsafe.Sizeof(c128))
|
||||
|
||||
// 复数的创建方式
|
||||
c1 := 1 + 2i // 直接创建
|
||||
c2 := complex(3, 4) // 使用 complex 函数
|
||||
c3 := complex(float64(5), 6) // 指定类型
|
||||
|
||||
fmt.Printf(" 复数创建方式:\n")
|
||||
fmt.Printf(" 直接创建: %v\n", c1)
|
||||
fmt.Printf(" complex函数: %v\n", c2)
|
||||
fmt.Printf(" 指定类型: %v\n", c3)
|
||||
|
||||
// 复数的实部和虚部
|
||||
fmt.Printf(" 复数的实部和虚部:\n")
|
||||
fmt.Printf(" %v 的实部: %.1f\n", c2, real(c2))
|
||||
fmt.Printf(" %v 的虚部: %.1f\n", c2, imag(c2))
|
||||
|
||||
// 复数运算
|
||||
sum := c1 + c2
|
||||
product := c1 * c2
|
||||
|
||||
fmt.Printf(" 复数运算:\n")
|
||||
fmt.Printf(" %v + %v = %v\n", c1, c2, sum)
|
||||
fmt.Printf(" %v * %v = %v\n", c1, c2, product)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateBooleanType 演示布尔类型
|
||||
func demonstrateBooleanType() {
|
||||
fmt.Println("4. 布尔类型:")
|
||||
|
||||
var b1 bool = true
|
||||
var b2 bool = false
|
||||
var b3 bool // 零值是 false
|
||||
|
||||
fmt.Printf(" 基本布尔值:\n")
|
||||
fmt.Printf(" b1: %t (大小: %d 字节)\n", b1, unsafe.Sizeof(b1))
|
||||
fmt.Printf(" b2: %t\n", b2)
|
||||
fmt.Printf(" b3 (零值): %t\n", b3)
|
||||
|
||||
// 布尔运算
|
||||
fmt.Printf(" 布尔运算:\n")
|
||||
fmt.Printf(" true && false = %t\n", true && false)
|
||||
fmt.Printf(" true || false = %t\n", true || false)
|
||||
fmt.Printf(" !true = %t\n", !true)
|
||||
fmt.Printf(" !false = %t\n", !false)
|
||||
|
||||
// 比较运算产生布尔值
|
||||
x, y := 10, 20
|
||||
fmt.Printf(" 比较运算:\n")
|
||||
fmt.Printf(" %d == %d: %t\n", x, y, x == y)
|
||||
fmt.Printf(" %d != %d: %t\n", x, y, x != y)
|
||||
fmt.Printf(" %d < %d: %t\n", x, y, x < y)
|
||||
fmt.Printf(" %d > %d: %t\n", x, y, x > y)
|
||||
fmt.Printf(" %d <= %d: %t\n", x, y, x <= y)
|
||||
fmt.Printf(" %d >= %d: %t\n", x, y, x >= y)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateStringType 演示字符串类型
|
||||
func demonstrateStringType() {
|
||||
fmt.Println("5. 字符串类型:")
|
||||
|
||||
var s1 string = "Hello, World!"
|
||||
var s2 string = "你好,世界!"
|
||||
var s3 string // 零值是空字符串 ""
|
||||
|
||||
fmt.Printf(" 基本字符串:\n")
|
||||
fmt.Printf(" s1: \"%s\" (长度: %d, 大小: %d 字节)\n", s1, len(s1), unsafe.Sizeof(s1))
|
||||
fmt.Printf(" s2: \"%s\" (长度: %d)\n", s2, len(s2))
|
||||
fmt.Printf(" s3 (零值): \"%s\"\n", s3)
|
||||
|
||||
// 字符串是不可变的
|
||||
fmt.Printf(" 字符串特性:\n")
|
||||
fmt.Printf(" 字符串是不可变的(immutable)\n")
|
||||
fmt.Printf(" 字符串是 UTF-8 编码的\n")
|
||||
|
||||
// 字符串操作
|
||||
fmt.Printf(" 字符串操作:\n")
|
||||
concatenated := s1 + " " + s2
|
||||
fmt.Printf(" 连接: \"%s\"\n", concatenated)
|
||||
|
||||
// 原始字符串字面量
|
||||
rawString := `这是一个原始字符串
|
||||
可以包含换行符
|
||||
和 "双引号" 以及 \n 这样的字符`
|
||||
|
||||
fmt.Printf(" 原始字符串:\n")
|
||||
fmt.Printf(" %s\n", rawString)
|
||||
|
||||
// 字符串转义序列
|
||||
escaped := "制表符:\t换行符:\n引号:\"反斜杠:\\"
|
||||
fmt.Printf(" 转义序列:\n")
|
||||
fmt.Printf(" %s\n", escaped)
|
||||
|
||||
// 字符串索引和切片
|
||||
fmt.Printf(" 字符串索引和切片:\n")
|
||||
str := "Hello"
|
||||
fmt.Printf(" str[0]: %c (字节值: %d)\n", str[0], str[0])
|
||||
fmt.Printf(" str[1:4]: \"%s\"\n", str[1:4])
|
||||
fmt.Printf(" str[:3]: \"%s\"\n", str[:3])
|
||||
fmt.Printf(" str[2:]: \"%s\"\n", str[2:])
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateCharacterTypes 演示字符类型
|
||||
func demonstrateCharacterTypes() {
|
||||
fmt.Println("6. 字符类型:")
|
||||
|
||||
// byte 类型(uint8 的别名)
|
||||
var b byte = 'A'
|
||||
fmt.Printf(" byte 类型:\n")
|
||||
fmt.Printf(" 字符 'A': %c (ASCII值: %d, 大小: %d 字节)\n", b, b, unsafe.Sizeof(b))
|
||||
|
||||
// rune 类型(int32 的别名,用于 Unicode 字符)
|
||||
var r1 rune = 'A'
|
||||
var r2 rune = '中'
|
||||
var r3 rune = '🚀'
|
||||
|
||||
fmt.Printf(" rune 类型:\n")
|
||||
fmt.Printf(" 字符 'A': %c (Unicode值: %d, 大小: %d 字节)\n", r1, r1, unsafe.Sizeof(r1))
|
||||
fmt.Printf(" 字符 '中': %c (Unicode值: %d)\n", r2, r2)
|
||||
fmt.Printf(" 字符 '🚀': %c (Unicode值: %d)\n", r3, r3)
|
||||
|
||||
// 字符串遍历
|
||||
fmt.Printf(" 字符串遍历:\n")
|
||||
str := "Hello世界"
|
||||
|
||||
fmt.Printf(" 按字节遍历:\n")
|
||||
for i := 0; i < len(str); i++ {
|
||||
fmt.Printf(" [%d]: %c (%d)\n", i, str[i], str[i])
|
||||
}
|
||||
|
||||
fmt.Printf(" 按字符遍历 (range):\n")
|
||||
for i, r := range str {
|
||||
fmt.Printf(" [%d]: %c (%d)\n", i, r, r)
|
||||
}
|
||||
|
||||
// Unicode 转义
|
||||
fmt.Printf(" Unicode 转义:\n")
|
||||
unicode1 := '\u4e2d' // 中
|
||||
unicode2 := '\U0001F680' // 🚀
|
||||
fmt.Printf(" \\u4e2d: %c\n", unicode1)
|
||||
fmt.Printf(" \\U0001F680: %c\n", unicode2)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateTypeConversion 演示类型转换
|
||||
func demonstrateTypeConversion() {
|
||||
fmt.Println("7. 类型转换:")
|
||||
|
||||
// 数值类型转换
|
||||
var i int = 42
|
||||
var f float64 = float64(i) // int 转 float64
|
||||
var ui uint = uint(i) // int 转 uint
|
||||
|
||||
fmt.Printf(" 数值类型转换:\n")
|
||||
fmt.Printf(" int %d -> float64 %.1f\n", i, f)
|
||||
fmt.Printf(" int %d -> uint %d\n", i, ui)
|
||||
|
||||
// 注意:Go 不支持隐式类型转换
|
||||
var i32 int32 = 100
|
||||
var i64 int64 = int64(i32) // 必须显式转换
|
||||
fmt.Printf(" int32 %d -> int64 %d\n", i32, i64)
|
||||
|
||||
// 字符串和数值转换需要使用 strconv 包
|
||||
// 这里只演示字符和数值的转换
|
||||
var ch byte = 65
|
||||
var chStr string = string(ch)
|
||||
fmt.Printf(" 字符转换:\n")
|
||||
fmt.Printf(" byte %d -> string \"%s\"\n", ch, chStr)
|
||||
|
||||
var r rune = 20013 // '中' 的 Unicode 值
|
||||
var rStr string = string(r)
|
||||
fmt.Printf(" rune %d -> string \"%s\"\n", r, rStr)
|
||||
|
||||
// 字符串转字节切片和字符切片
|
||||
str := "Hello世界"
|
||||
bytes := []byte(str)
|
||||
runes := []rune(str)
|
||||
|
||||
fmt.Printf(" 字符串转换:\n")
|
||||
fmt.Printf(" string -> []byte: %v\n", bytes)
|
||||
fmt.Printf(" string -> []rune: %v\n", runes)
|
||||
fmt.Printf(" []byte -> string: \"%s\"\n", string(bytes))
|
||||
fmt.Printf(" []rune -> string: \"%s\"\n", string(runes))
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateTypeInfo 演示类型信息
|
||||
func demonstrateTypeInfo() {
|
||||
fmt.Println("8. 类型信息:")
|
||||
|
||||
// 使用 %T 打印类型信息
|
||||
var i int = 42
|
||||
var f float64 = 3.14
|
||||
var s string = "Hello"
|
||||
var b bool = true
|
||||
var c complex128 = 1 + 2i
|
||||
|
||||
fmt.Printf(" 类型信息:\n")
|
||||
fmt.Printf(" %v 的类型: %T\n", i, i)
|
||||
fmt.Printf(" %v 的类型: %T\n", f, f)
|
||||
fmt.Printf(" \"%v\" 的类型: %T\n", s, s)
|
||||
fmt.Printf(" %v 的类型: %T\n", b, b)
|
||||
fmt.Printf(" %v 的类型: %T\n", c, c)
|
||||
|
||||
// 类型别名
|
||||
type MyInt int
|
||||
type MyString string
|
||||
|
||||
var mi MyInt = 100
|
||||
var ms MyString = "自定义类型"
|
||||
|
||||
fmt.Printf(" 自定义类型:\n")
|
||||
fmt.Printf(" %v 的类型: %T\n", mi, mi)
|
||||
fmt.Printf(" \"%v\" 的类型: %T\n", ms, ms)
|
||||
|
||||
// 类型别名和原类型的转换
|
||||
var normalInt int = int(mi) // 需要显式转换
|
||||
fmt.Printf(" MyInt -> int: %d\n", normalInt)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
/*
|
||||
运行这个程序:
|
||||
go run 04-data-types.go
|
||||
|
||||
学习要点:
|
||||
1. Go 有丰富的基本数据类型,包括整数、浮点、复数、布尔、字符串
|
||||
2. 整数类型有有符号和无符号之分,大小从 8 位到 64 位
|
||||
3. int 和 uint 的大小取决于平台(32位或64位)
|
||||
4. 浮点数有精度限制,比较时要注意精度问题
|
||||
5. 字符串是 UTF-8 编码的,不可变的
|
||||
6. byte 用于 ASCII 字符,rune 用于 Unicode 字符
|
||||
7. Go 不支持隐式类型转换,必须显式转换
|
||||
8. 可以定义类型别名,但需要显式转换
|
||||
|
||||
选择类型的建议:
|
||||
1. 整数:一般使用 int,需要特定大小时使用 int8/16/32/64
|
||||
2. 浮点:一般使用 float64,性能要求高时使用 float32
|
||||
3. 字符:ASCII 字符用 byte,Unicode 字符用 rune
|
||||
4. 字符串:使用 string,需要修改时转换为 []byte 或 []rune
|
||||
|
||||
注意事项:
|
||||
1. 不同类型之间不能直接运算,必须转换为相同类型
|
||||
2. 浮点数比较要考虑精度问题
|
||||
3. 字符串索引访问的是字节,不是字符
|
||||
4. 使用 range 遍历字符串可以正确处理 Unicode 字符
|
||||
*/
|
475
golang-learning/01-basics/05-operators.go
Normal file
475
golang-learning/01-basics/05-operators.go
Normal file
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
05-operators.go - Go 语言运算符详解
|
||||
|
||||
学习目标:
|
||||
1. 掌握算术运算符的使用
|
||||
2. 理解比较运算符的规则
|
||||
3. 学会逻辑运算符的应用
|
||||
4. 了解位运算符的用法
|
||||
5. 掌握赋值运算符的使用
|
||||
6. 理解运算符的优先级
|
||||
|
||||
知识点:
|
||||
- 算术运算符 (+, -, *, /, %, ++, --)
|
||||
- 比较运算符 (==, !=, <, <=, >, >=)
|
||||
- 逻辑运算符 (&&, ||, !)
|
||||
- 位运算符 (&, |, ^, <<, >>)
|
||||
- 赋值运算符 (=, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=)
|
||||
- 其他运算符 (&, *, <-)
|
||||
- 运算符优先级
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== Go 语言运算符详解 ===\n")
|
||||
|
||||
// 演示算术运算符
|
||||
demonstrateArithmeticOperators()
|
||||
|
||||
// 演示比较运算符
|
||||
demonstrateComparisonOperators()
|
||||
|
||||
// 演示逻辑运算符
|
||||
demonstrateLogicalOperators()
|
||||
|
||||
// 演示位运算符
|
||||
demonstrateBitwiseOperators()
|
||||
|
||||
// 演示赋值运算符
|
||||
demonstrateAssignmentOperators()
|
||||
|
||||
// 演示其他运算符
|
||||
demonstrateOtherOperators()
|
||||
|
||||
// 演示运算符优先级
|
||||
demonstrateOperatorPrecedence()
|
||||
|
||||
// 演示实际应用示例
|
||||
demonstratePracticalExamples()
|
||||
}
|
||||
|
||||
// demonstrateArithmeticOperators 演示算术运算符
|
||||
func demonstrateArithmeticOperators() {
|
||||
fmt.Println("1. 算术运算符:")
|
||||
|
||||
a, b := 15, 4
|
||||
|
||||
fmt.Printf(" 基本算术运算 (a=%d, b=%d):\n", a, b)
|
||||
fmt.Printf(" a + b = %d + %d = %d\n", a, b, a+b)
|
||||
fmt.Printf(" a - b = %d - %d = %d\n", a, b, a-b)
|
||||
fmt.Printf(" a * b = %d * %d = %d\n", a, b, a*b)
|
||||
fmt.Printf(" a / b = %d / %d = %d\n", a, b, a/b) // 整数除法
|
||||
fmt.Printf(" a %% b = %d %% %d = %d\n", a, b, a%b) // 取余
|
||||
|
||||
// 浮点数除法
|
||||
fa, fb := 15.0, 4.0
|
||||
fmt.Printf(" 浮点数除法:\n")
|
||||
fmt.Printf(" %.1f / %.1f = %.2f\n", fa, fb, fa/fb)
|
||||
|
||||
// 自增和自减运算符
|
||||
fmt.Printf(" 自增和自减运算符:\n")
|
||||
x := 10
|
||||
fmt.Printf(" x = %d\n", x)
|
||||
x++ // x = x + 1
|
||||
fmt.Printf(" x++ 后: %d\n", x)
|
||||
x-- // x = x - 1
|
||||
fmt.Printf(" x-- 后: %d\n", x)
|
||||
|
||||
// 注意:Go 中的 ++ 和 -- 是语句,不是表达式
|
||||
fmt.Printf(" 注意: Go 中 ++ 和 -- 是语句,不能用在表达式中\n")
|
||||
// y := x++ // 编译错误
|
||||
// z := ++x // 编译错误,Go 没有前置 ++
|
||||
|
||||
// 一元运算符
|
||||
fmt.Printf(" 一元运算符:\n")
|
||||
positive := +10
|
||||
negative := -10
|
||||
fmt.Printf(" +10 = %d\n", positive)
|
||||
fmt.Printf(" -10 = %d\n", negative)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateComparisonOperators 演示比较运算符
|
||||
func demonstrateComparisonOperators() {
|
||||
fmt.Println("2. 比较运算符:")
|
||||
|
||||
a, b := 10, 20
|
||||
|
||||
fmt.Printf(" 数值比较 (a=%d, b=%d):\n", a, b)
|
||||
fmt.Printf(" a == b: %d == %d = %t\n", a, b, a == b)
|
||||
fmt.Printf(" a != b: %d != %d = %t\n", a, b, a != b)
|
||||
fmt.Printf(" a < b: %d < %d = %t\n", a, b, a < b)
|
||||
fmt.Printf(" a <= b: %d <= %d = %t\n", a, b, a <= b)
|
||||
fmt.Printf(" a > b: %d > %d = %t\n", a, b, a > b)
|
||||
fmt.Printf(" a >= b: %d >= %d = %t\n", a, b, a >= b)
|
||||
|
||||
// 字符串比较
|
||||
s1, s2 := "apple", "banana"
|
||||
fmt.Printf(" 字符串比较 (s1=\"%s\", s2=\"%s\"):\n", s1, s2)
|
||||
fmt.Printf(" s1 == s2: %t\n", s1 == s2)
|
||||
fmt.Printf(" s1 < s2: %t (按字典序)\n", s1 < s2)
|
||||
fmt.Printf(" s1 > s2: %t\n", s1 > s2)
|
||||
|
||||
// 布尔值比较
|
||||
bool1, bool2 := true, false
|
||||
fmt.Printf(" 布尔值比较:\n")
|
||||
fmt.Printf(" true == false: %t\n", bool1 == bool2)
|
||||
fmt.Printf(" true != false: %t\n", bool1 != bool2)
|
||||
|
||||
// 注意:不同类型不能直接比较
|
||||
fmt.Printf(" 注意: 不同类型不能直接比较,需要类型转换\n")
|
||||
var i int = 10
|
||||
var f float64 = 10.0
|
||||
// fmt.Println(i == f) // 编译错误
|
||||
fmt.Printf(" int(10) == float64(10.0): %t\n", float64(i) == f)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateLogicalOperators 演示逻辑运算符
|
||||
func demonstrateLogicalOperators() {
|
||||
fmt.Println("3. 逻辑运算符:")
|
||||
|
||||
a, b := true, false
|
||||
|
||||
fmt.Printf(" 基本逻辑运算 (a=%t, b=%t):\n", a, b)
|
||||
fmt.Printf(" a && b: %t && %t = %t (逻辑与)\n", a, b, a && b)
|
||||
fmt.Printf(" a || b: %t || %t = %t (逻辑或)\n", a, b, a || b)
|
||||
fmt.Printf(" !a: !%t = %t (逻辑非)\n", a, !a)
|
||||
fmt.Printf(" !b: !%t = %t\n", b, !b)
|
||||
|
||||
// 真值表
|
||||
fmt.Printf(" 逻辑运算真值表:\n")
|
||||
fmt.Printf(" A | B | A&&B | A||B | !A\n")
|
||||
fmt.Printf(" ------|-------|-------|-------|------\n")
|
||||
fmt.Printf(" true | true | %t | %t | %t\n", true && true, true || true, !true)
|
||||
fmt.Printf(" true | false | %t| %t | %t\n", true && false, true || false, !true)
|
||||
fmt.Printf(" false | true | %t| %t | %t\n", false && true, false || true, !false)
|
||||
fmt.Printf(" false | false | %t| %t | %t\n", false && false, false || false, !false)
|
||||
|
||||
// 短路求值
|
||||
fmt.Printf(" 短路求值演示:\n")
|
||||
x, y := 5, 0
|
||||
|
||||
// && 短路:如果左边是 false,右边不会执行
|
||||
fmt.Printf(" 短路与: (x > 10) && (y != 0)\n")
|
||||
result1 := (x > 10) && (y != 0)
|
||||
fmt.Printf(" 结果: %t (右边条件不会被检查)\n", result1)
|
||||
|
||||
// || 短路:如果左边是 true,右边不会执行
|
||||
fmt.Printf(" 短路或: (x > 0) || (y != 0)\n")
|
||||
result2 := (x > 0) || (y != 0)
|
||||
fmt.Printf(" 结果: %t (右边条件不会被检查)\n", result2)
|
||||
|
||||
// 复合逻辑表达式
|
||||
age := 25
|
||||
hasLicense := true
|
||||
hasInsurance := false
|
||||
|
||||
canDrive := age >= 18 && hasLicense && hasInsurance
|
||||
fmt.Printf(" 复合条件判断:\n")
|
||||
fmt.Printf(" 年龄: %d, 有驾照: %t, 有保险: %t\n", age, hasLicense, hasInsurance)
|
||||
fmt.Printf(" 可以开车: %t\n", canDrive)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateBitwiseOperators 演示位运算符
|
||||
func demonstrateBitwiseOperators() {
|
||||
fmt.Println("4. 位运算符:")
|
||||
|
||||
a, b := 12, 10 // 12 = 1100, 10 = 1010 (二进制)
|
||||
|
||||
fmt.Printf(" 位运算 (a=%d, b=%d):\n", a, b)
|
||||
fmt.Printf(" a 的二进制: %08b\n", a)
|
||||
fmt.Printf(" b 的二进制: %08b\n", b)
|
||||
fmt.Printf(" a & b: %08b = %d (按位与)\n", a & b, a & b)
|
||||
fmt.Printf(" a | b: %08b = %d (按位或)\n", a | b, a | b)
|
||||
fmt.Printf(" a ^ b: %08b = %d (按位异或)\n", a ^ b, a ^ b)
|
||||
fmt.Printf(" ^a: %08b = %d (按位取反)\n", ^a, ^a)
|
||||
|
||||
// 位移运算
|
||||
fmt.Printf(" 位移运算:\n")
|
||||
x := 8 // 1000 (二进制)
|
||||
fmt.Printf(" x = %d (%08b)\n", x, x)
|
||||
fmt.Printf(" x << 1: %08b = %d (左移1位)\n", x << 1, x << 1)
|
||||
fmt.Printf(" x << 2: %08b = %d (左移2位)\n", x << 2, x << 2)
|
||||
fmt.Printf(" x >> 1: %08b = %d (右移1位)\n", x >> 1, x >> 1)
|
||||
fmt.Printf(" x >> 2: %08b = %d (右移2位)\n", x >> 2, x >> 2)
|
||||
|
||||
// 位运算的实际应用
|
||||
fmt.Printf(" 位运算应用示例:\n")
|
||||
|
||||
// 检查奇偶性
|
||||
num := 15
|
||||
isEven := (num & 1) == 0
|
||||
fmt.Printf(" %d 是偶数: %t (使用 n&1==0 检查)\n", num, isEven)
|
||||
|
||||
// 快速乘除法(2的幂)
|
||||
fmt.Printf(" 快速乘除法:\n")
|
||||
fmt.Printf(" %d * 4 = %d << 2 = %d\n", num, num, num << 2)
|
||||
fmt.Printf(" %d / 4 = %d >> 2 = %d\n", num, num, num >> 2)
|
||||
|
||||
// 设置、清除、切换位
|
||||
flags := 0
|
||||
fmt.Printf(" 位标志操作:\n")
|
||||
fmt.Printf(" 初始标志: %08b\n", flags)
|
||||
|
||||
flags |= (1 << 2) // 设置第2位
|
||||
fmt.Printf(" 设置第2位: %08b\n", flags)
|
||||
|
||||
flags &^= (1 << 2) // 清除第2位
|
||||
fmt.Printf(" 清除第2位: %08b\n", flags)
|
||||
|
||||
flags ^= (1 << 1) // 切换第1位
|
||||
fmt.Printf(" 切换第1位: %08b\n", flags)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateAssignmentOperators 演示赋值运算符
|
||||
func demonstrateAssignmentOperators() {
|
||||
fmt.Println("5. 赋值运算符:")
|
||||
|
||||
// 基本赋值
|
||||
var x int = 10
|
||||
fmt.Printf(" 基本赋值: x = %d\n", x)
|
||||
|
||||
// 复合赋值运算符
|
||||
fmt.Printf(" 复合赋值运算符:\n")
|
||||
|
||||
x += 5 // x = x + 5
|
||||
fmt.Printf(" x += 5: x = %d\n", x)
|
||||
|
||||
x -= 3 // x = x - 3
|
||||
fmt.Printf(" x -= 3: x = %d\n", x)
|
||||
|
||||
x *= 2 // x = x * 2
|
||||
fmt.Printf(" x *= 2: x = %d\n", x)
|
||||
|
||||
x /= 4 // x = x / 4
|
||||
fmt.Printf(" x /= 4: x = %d\n", x)
|
||||
|
||||
x %= 3 // x = x % 3
|
||||
fmt.Printf(" x %%= 3: x = %d\n", x)
|
||||
|
||||
// 位运算赋值
|
||||
fmt.Printf(" 位运算赋值:\n")
|
||||
y := 12 // 1100
|
||||
fmt.Printf(" y = %d (%04b)\n", y, y)
|
||||
|
||||
y &= 10 // y = y & 10 (1010)
|
||||
fmt.Printf(" y &= 10: y = %d (%04b)\n", y, y)
|
||||
|
||||
y |= 5 // y = y | 5 (0101)
|
||||
fmt.Printf(" y |= 5: y = %d (%04b)\n", y, y)
|
||||
|
||||
y ^= 3 // y = y ^ 3 (0011)
|
||||
fmt.Printf(" y ^= 3: y = %d (%04b)\n", y, y)
|
||||
|
||||
y <<= 1 // y = y << 1
|
||||
fmt.Printf(" y <<= 1: y = %d (%04b)\n", y, y)
|
||||
|
||||
y >>= 2 // y = y >> 2
|
||||
fmt.Printf(" y >>= 2: y = %d (%04b)\n", y, y)
|
||||
|
||||
// 多重赋值
|
||||
fmt.Printf(" 多重赋值:\n")
|
||||
a, b, c := 1, 2, 3
|
||||
fmt.Printf(" a, b, c := 1, 2, 3: a=%d, b=%d, c=%d\n", a, b, c)
|
||||
|
||||
// 交换变量
|
||||
a, b = b, a
|
||||
fmt.Printf(" a, b = b, a: a=%d, b=%d (交换)\n", a, b)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateOtherOperators 演示其他运算符
|
||||
func demonstrateOtherOperators() {
|
||||
fmt.Println("6. 其他运算符:")
|
||||
|
||||
// 地址运算符 &
|
||||
x := 42
|
||||
ptr := &x
|
||||
fmt.Printf(" 地址运算符 &:\n")
|
||||
fmt.Printf(" x = %d\n", x)
|
||||
fmt.Printf(" &x = %p (x的地址)\n", ptr)
|
||||
|
||||
// 解引用运算符 *
|
||||
fmt.Printf(" 解引用运算符 *:\n")
|
||||
fmt.Printf(" *ptr = %d (ptr指向的值)\n", *ptr)
|
||||
|
||||
// 修改指针指向的值
|
||||
*ptr = 100
|
||||
fmt.Printf(" 修改 *ptr = 100 后, x = %d\n", x)
|
||||
|
||||
// 通道运算符 <- (这里只是语法演示,详细内容在并发章节)
|
||||
fmt.Printf(" 通道运算符 <- (语法演示):\n")
|
||||
ch := make(chan int, 1)
|
||||
ch <- 42 // 发送值到通道
|
||||
value := <-ch // 从通道接收值
|
||||
fmt.Printf(" 通道发送和接收: %d\n", value)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateOperatorPrecedence 演示运算符优先级
|
||||
func demonstrateOperatorPrecedence() {
|
||||
fmt.Println("7. 运算符优先级:")
|
||||
|
||||
// 算术运算符优先级
|
||||
result1 := 2 + 3 * 4
|
||||
result2 := (2 + 3) * 4
|
||||
fmt.Printf(" 算术运算优先级:\n")
|
||||
fmt.Printf(" 2 + 3 * 4 = %d (乘法优先)\n", result1)
|
||||
fmt.Printf(" (2 + 3) * 4 = %d (括号改变优先级)\n", result2)
|
||||
|
||||
// 比较和逻辑运算符优先级
|
||||
a, b, c := 5, 10, 15
|
||||
result3 := a < b && b < c
|
||||
result4 := a < b || b > c && c > a
|
||||
fmt.Printf(" 比较和逻辑运算优先级:\n")
|
||||
fmt.Printf(" %d < %d && %d < %d = %t\n", a, b, b, c, result3)
|
||||
fmt.Printf(" %d < %d || %d > %d && %d > %d = %t\n", a, b, b, c, c, a, result4)
|
||||
|
||||
// 位运算符优先级
|
||||
x := 6 // 110
|
||||
y := 3 // 011
|
||||
result5 := x & y | x ^ y
|
||||
result6 := x & (y | x) ^ y
|
||||
fmt.Printf(" 位运算优先级:\n")
|
||||
fmt.Printf(" %d & %d | %d ^ %d = %d\n", x, y, x, y, result5)
|
||||
fmt.Printf(" %d & (%d | %d) ^ %d = %d\n", x, y, x, y, result6)
|
||||
|
||||
// 运算符优先级表(从高到低)
|
||||
fmt.Printf(" 运算符优先级表(从高到低):\n")
|
||||
fmt.Printf(" 1. * / %% << >> & &^\n")
|
||||
fmt.Printf(" 2. + - | ^\n")
|
||||
fmt.Printf(" 3. == != < <= > >=\n")
|
||||
fmt.Printf(" 4. &&\n")
|
||||
fmt.Printf(" 5. ||\n")
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstratePracticalExamples 演示实际应用示例
|
||||
func demonstratePracticalExamples() {
|
||||
fmt.Println("8. 实际应用示例:")
|
||||
|
||||
// 示例1: 计算器功能
|
||||
fmt.Printf(" 示例1 - 简单计算器:\n")
|
||||
num1, num2 := 15.5, 4.2
|
||||
operator := "+"
|
||||
|
||||
var result float64
|
||||
switch operator {
|
||||
case "+":
|
||||
result = num1 + num2
|
||||
case "-":
|
||||
result = num1 - num2
|
||||
case "*":
|
||||
result = num1 * num2
|
||||
case "/":
|
||||
if num2 != 0 {
|
||||
result = num1 / num2
|
||||
} else {
|
||||
fmt.Printf(" 错误: 除数不能为零\n")
|
||||
return
|
||||
}
|
||||
}
|
||||
fmt.Printf(" %.1f %s %.1f = %.2f\n", num1, operator, num2, result)
|
||||
|
||||
// 示例2: 判断闰年
|
||||
fmt.Printf(" 示例2 - 判断闰年:\n")
|
||||
year := 2024
|
||||
isLeapYear := (year%4 == 0 && year%100 != 0) || (year%400 == 0)
|
||||
fmt.Printf(" %d年是闰年: %t\n", year, isLeapYear)
|
||||
|
||||
// 示例3: 位掩码操作
|
||||
fmt.Printf(" 示例3 - 权限系统 (位掩码):\n")
|
||||
const (
|
||||
READ = 1 << 0 // 001
|
||||
WRITE = 1 << 1 // 010
|
||||
EXECUTE = 1 << 2 // 100
|
||||
)
|
||||
|
||||
// 设置权限
|
||||
permissions := READ | WRITE // 011
|
||||
fmt.Printf(" 初始权限: %03b (读:%t, 写:%t, 执行:%t)\n",
|
||||
permissions,
|
||||
permissions&READ != 0,
|
||||
permissions&WRITE != 0,
|
||||
permissions&EXECUTE != 0)
|
||||
|
||||
// 添加执行权限
|
||||
permissions |= EXECUTE // 111
|
||||
fmt.Printf(" 添加执行权限: %03b (读:%t, 写:%t, 执行:%t)\n",
|
||||
permissions,
|
||||
permissions&READ != 0,
|
||||
permissions&WRITE != 0,
|
||||
permissions&EXECUTE != 0)
|
||||
|
||||
// 移除写权限
|
||||
permissions &^= WRITE // 101
|
||||
fmt.Printf(" 移除写权限: %03b (读:%t, 写:%t, 执行:%t)\n",
|
||||
permissions,
|
||||
permissions&READ != 0,
|
||||
permissions&WRITE != 0,
|
||||
permissions&EXECUTE != 0)
|
||||
|
||||
// 示例4: 条件表达式模拟
|
||||
fmt.Printf(" 示例4 - 条件表达式模拟:\n")
|
||||
score := 85
|
||||
var grade string
|
||||
|
||||
// Go 没有三元运算符,使用 if-else
|
||||
if score >= 90 {
|
||||
grade = "A"
|
||||
} else if score >= 80 {
|
||||
grade = "B"
|
||||
} else if score >= 70 {
|
||||
grade = "C"
|
||||
} else if score >= 60 {
|
||||
grade = "D"
|
||||
} else {
|
||||
grade = "F"
|
||||
}
|
||||
|
||||
fmt.Printf(" 分数 %d 对应等级: %s\n", score, grade)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
/*
|
||||
运行这个程序:
|
||||
go run 05-operators.go
|
||||
|
||||
学习要点:
|
||||
1. Go 支持丰富的运算符,包括算术、比较、逻辑、位运算等
|
||||
2. ++ 和 -- 在 Go 中是语句,不是表达式,不能用在赋值中
|
||||
3. Go 不支持隐式类型转换,不同类型不能直接比较或运算
|
||||
4. 逻辑运算符支持短路求值,可以提高效率和安全性
|
||||
5. 位运算符在系统编程和性能优化中很有用
|
||||
6. 复合赋值运算符可以简化代码
|
||||
7. 运算符有优先级,使用括号可以改变优先级
|
||||
8. Go 没有三元运算符,使用 if-else 代替
|
||||
|
||||
实际应用:
|
||||
1. 算术运算符用于数学计算
|
||||
2. 比较运算符用于条件判断
|
||||
3. 逻辑运算符用于复合条件
|
||||
4. 位运算符用于标志位操作、权限系统等
|
||||
5. 赋值运算符用于变量更新
|
||||
|
||||
注意事项:
|
||||
1. 除法运算要注意整数除法和浮点除法的区别
|
||||
2. 取余运算的结果符号与被除数相同
|
||||
3. 位运算时要注意数据类型的位数
|
||||
4. 使用逻辑运算符时要注意短路求值的特性
|
||||
5. 复杂表达式建议使用括号明确优先级
|
||||
*/
|
23
golang-learning/01-basics/README.md
Normal file
23
golang-learning/01-basics/README.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# 第一章:基础语法
|
||||
|
||||
本章将介绍 Go 语言的基础语法,包括程序结构、变量、常量、数据类型和运算符。
|
||||
|
||||
## 学习目标
|
||||
- 理解 Go 程序的基本结构
|
||||
- 掌握变量声明和初始化的方法
|
||||
- 了解 Go 的基本数据类型
|
||||
- 学会使用各种运算符
|
||||
|
||||
## 文件列表
|
||||
- `01-hello-world.go` - Hello World 程序和基本结构
|
||||
- `02-variables.go` - 变量声明和初始化
|
||||
- `03-constants.go` - 常量定义和使用
|
||||
- `04-data-types.go` - 基本数据类型
|
||||
- `05-operators.go` - 运算符使用
|
||||
|
||||
## 运行示例
|
||||
```bash
|
||||
go run 01-hello-world.go
|
||||
go run 02-variables.go
|
||||
# ... 依此类推
|
||||
```
|
Reference in New Issue
Block a user