当前位置: 首页 > news >正文

Go语言变量声明与初始化详解

变量声明与初始化

var关键字声明

Go语言使用var关键字声明变量,语法格式为:

var 变量名 类型 = 表达式

其中类型和表达式可以省略一个:

// 完整声明方式
var name string = "Alice"  // 显式指定类型为string
var count int = 100        // 显式指定类型为int
var isActive bool = true   // 显式指定类型为bool// 省略类型,由编译器推断
var age = 25               // 编译器推断为int类型
var price = 99.99          // 编译器推断为float64类型
var greeting = "Hello"     // 编译器推断为string类型// 省略表达式,初始化为零值
var score float64          // 初始化为0.0
var username string        // 初始化为空字符串""
var isReady bool           // 初始化为false

短变量声明(:=)

短变量声明是Go的特色语法,只能在函数内部使用:

func main() {// 基本短变量声明name := "Alice"      // 等价于 var name string = "Alice"age := 25            // 等价于 var age int = 25ratio := 3.14        // 等价于 var ratio float64 = 3.14// 多变量短声明x, y := 10, "hello"  // 同时声明int和string变量// 在if、for等语句中的短声明if count := getCount(); count > 0 {fmt.Println(count)}
}

这种声明方式的特点:

  1. 必须包含初始值:不能只声明不赋值

    var x int      // 合法
    x :=           // 非法,必须提供初始值
    

  2. 不能指定类型:类型由编译器根据初始值推断

    x := int(10)   // 虽然可以这样写,但不推荐
    

  3. 简洁高效:是Go推荐的方式,特别是在函数内部

    // 推荐
    count := 0// 不推荐
    var count int = 0
    

  4. 作用域限制:只能在函数内部使用,不能在包级别使用

类型推断

Go语言的类型推断能力很强,例如:

// 基本类型推断
var score = 98.5       // 推断为float64
var name = "Bob"       // 推断为string
var enabled = true     // 推断为bool
var list = []int{1,2,3} // 推断为[]int// 复合类型推断
var person = struct{Name stringAge  int
}{Name: "Alice",Age:  30,
}// 函数返回值推断
func getValue() interface{} {return 42
}
var value = getValue()  // 推断为interface{}

特殊情况下需要显式指定类型:

// 需要特定精度
var temperature float32 = 36.5  // 明确需要float32而非默认的float64// 需要特定整数类型
var port uint16 = 8080          // 网络端口通常使用uint16// 实现特定接口
var writer io.Writer = os.Stdout // 明确接口类型

零值(Zero Value)

Go为未初始化的变量提供默认零值:

类型零值
数值类型0
布尔类型false
字符串""
指针nil
接口nil
切片nil
映射nil
通道nil
函数nil
结构体各字段零值

零值在实际开发中的典型应用:

// 计数器初始化
var requestCount int  // 自动初始化为0
requestCount++// 延迟初始化
var logs []string     // 初始为nil,可以后续判断
if logs == nil {logs = make([]string, 0)
}// 配置检查
var config *Config    // 初始为nil
if config != nil {config.Load()
}// 结构体初始化
type User struct {Name stringAge  int
}
var u User  // u.Name为"",u.Age为0

变量命名规则与最佳实践

命名规范

可见性规则
  1. 导出(公开)变量:首字母大写,包外可见

    var MaxRetries = 3      // 其他包可以访问
    var DefaultTimeout = 30 // 其他包可以访问
    

  2. 非导出(私有)变量:首字母小写,仅包内可见

    var maxRetries = 3      // 只在当前包内可用
    var defaultTimeout = 30 // 只在当前包内可用
    

命名风格
  1. 驼峰命名法

    var userName string     // 小驼峰
    var DatabaseConfig struct{} // 大驼峰
    

  2. 避免下划线(特殊常量除外)

    // 不推荐
    var user_name string
    var MAX_RETRIES = 3// 推荐
    var userName string
    var maxRetries = 3
    

  3. 避免使用关键字

    // 错误
    var var = "value"
    var func = "function"// 正确
    var variable = "value"
    var function = "func"
    

长度控制
  1. 短名称:适合局部变量和短作用域

    for i := 0; i < 10; i++ {sum += i
    }func process(data []byte) {buf := bytes.NewBuffer(data)// ...
    }
    

  2. 长名称:适合重要变量和全局变量

    var databaseConnectionPoolSize = 100
    var maximumAllowedFileSizeInBytes = 1024 * 1024 * 10
    

最佳实践示例

好的命名
// 清晰的意图
var maxRetries = 3             // 明确表示最大重试次数
var connectionTimeout = 30     // 明确表示连接超时时间(秒)
var dbConfig DatabaseConfig    // 类型明确,知道是数据库配置// 循环变量
for index, item := range items {processItem(index, item)
}// 布尔变量
var isEnabled bool            // 使用is前缀表示布尔值
var hasPermission = false     // 使用has前缀表示布尔值

不好的命名
// 缩写不明确
var mrt = 3                   // 不清楚mrt代表什么
var ct = 30                   // 不清楚ct代表什么// 风格不一致
var timeout_of_connection = 30 // 混合使用下划线和驼峰
var ConnectionTimeout = 30     // 全局变量却使用小写// 类型过于宽泛
var config interface{}        // 不知道具体是什么配置
var data []byte               // 不知道数据的用途// 无意义的单字母
var d Data                    // 不知道d代表什么
var s string                  // 不知道s代表什么

变量作用域与生命周期

作用域规则

局部变量
func calculate() {// 函数级作用域x := 10                // 在整个calculate函数内可见if y := 20; y > x {// 块级作用域z := 30            // 仅在if块内可见fmt.Println(x, y, z)}// fmt.Println(z)      // 错误:z未定义// fmt.Println(y)      // 错误:y未定义fmt.Println(x)         // 正确
}func anotherFunc() {// fmt.Println(x)      // 错误:x未定义
}

全局变量
package mainvar globalCount = 0        // 包内所有函数可见func increment() {globalCount++          // 可以访问和修改全局变量
}func printCount() {fmt.Println(globalCount) // 可以访问全局变量
}func main() {increment()printCount()           // 输出: 1
}

包级变量
// config/config.go
package config// 导出变量,其他包可访问
var AppName = "MyApp"     // 其他包可以通过config.AppName访问// 非导出变量,仅本包可用
var apiKey = "secret"     // 只能在config包内使用func GetAPIKey() string {return apiKey         // 包内函数可以访问非导出变量
}

生命周期管理

栈分配
func sum(a, b int) int {// 简单变量通常分配在栈上result := a + b// 函数返回后,栈上的变量自动释放return result
}func main() {s := sum(3, 4)  // 调用时在栈上分配空间fmt.Println(s)   // 使用完后栈空间自动回收
}

堆分配(逃逸分析)
// User 结构体定义
type User struct {Name stringAge  int
}// 返回指针,导致变量逃逸到堆
func createUser() *User {u := User{Name: "Alice", Age: 30}  // 编译器会让u逃逸到堆return &u                          // 因为返回指针,所以必须在堆上分配
}func main() {user := createUser()  // user指向堆上的User对象fmt.Println(user)     // 堆上对象由GC管理
}

查看逃逸分析结果

使用以下命令查看变量的逃逸分析情况:

go build -gcflags="-m -l" main.go

示例输出:

./main.go:10:6: can inline createUser
./main.go:17:6: can inline main
./main.go:18:16: inlining call to createUser
./main.go:11:2: moved to heap: u  # 表示u变量逃逸到了堆

基本数据类型与变量

基本数据类型详解

整型
// 平台相关整数
var a int = 10         // 32位系统上是int32,64位系统上是int64
var b uint = 20        // 无符号整数// 明确大小的整数
var c int32 = 30       // 32位有符号整数
var d int64 = 40       // 64位有符号整数
var e uint8 = 50       // 8位无符号整数(0-255)// 特殊别名
var f byte = 'A'       // uint8的别名,用于ASCII字符
var g rune = '中'      // int32的别名,用于Unicode字符// 不同进制表示
var h = 0xFF           // 十六进制
var i = 0755           // 八进制
var j = 0b1101         // 二进制

浮点型
// 标准浮点数
var f1 float32 = 3.1415926    // 单精度,约6-7位小数精度
var f2 float64 = 3.141592653589793 // 双精度,约15位小数精度(默认)// 科学计数法
var avogadro = 6.02214076e23  // 阿伏伽德罗常数
var planck = 6.62607015e-34   // 普朗克常数// 特殊浮点值
var posInf = math.Inf(1)      // 正无穷
var negInf = math.Inf(-1)     // 负无穷
var nan = math.NaN()          // 非数

布尔型
var isReady bool = true
var hasError = false// 布尔运算
a := true
b := false
fmt.Println(a && b)  // false
fmt.Println(a || b)  // true
fmt.Println(!a)     // false// 条件判断
if isReady && !hasError {proceed()
}

字符串
// 基本字符串
var name string = "张三"
var greeting = "Hello, 世界"// 原始字符串(反引号)
var query = `SELECT * FROM users 
WHERE name = "Alice"`  // 保留换行和引号// 字符串操作
s1 := "Hello"
s2 := "World"
combined := s1 + " " + s2  // 字符串连接
length := len(combined)    // 获取字节长度(不是字符数)// 字符串索引
firstByte := combined[0]   // 获取第一个字节(H)
// combined[0] = 'h'       // 错误:字符串不可变// Unicode处理
runeCount := utf8.RuneCountInString(combined) // 实际字符数

值类型 vs 引用类型

值类型示例
// 基本类型都是值类型
a := 10
b := a       // 值拷贝
b = 20       // 修改b不影响a
fmt.Println(a, b)  // 输出: 10 20// 数组是值类型
arr1 := [3]int{1, 2, 3}
arr2 := arr1        // 整个数组拷贝
arr2[0] = 100
fmt.Println(arr1)  // [1 2 3]
fmt.Println(arr2)  // [100 2 3]// 结构体是值类型
type Point struct {X, Y int
}
p1 := Point{1, 2}
p2 := p1            // 结构体拷贝
p2.X = 10
fmt.Println(p1)     // {1 2}
fmt.Println(p2)     // {10 2}

引用类型示例
// 切片是引用类型
slice1 := []int{1, 2, 3}
slice2 := slice1       // 引用同一个底层数组
slice2[0] = 100
fmt.Println(slice1)    // [100 2 3]
fmt.Println(slice2)    // [100 2 3]// 映射是引用类型
map1 := map[string]int{"a": 1, "b": 2}
map2 := map1           // 引用同一个map
map2["a"] = 100
fmt.Println(map1)      // map[a:100 b:2]
fmt.Println(map2)      // map[a:100 b:2]// 通道是引用类型
ch1 := make(chan int, 1)
ch2 := ch1             // 引用同一个通道
ch1 <- 42
fmt.Println(<-ch2)     // 42

指针操作
// 基本指针操作
x := 10
p := &x        // 获取x的地址
fmt.Println(*p) // 10 (解引用)
*p = 20        // 通过指针修改x的值
fmt.Println(x)  // 20// 结构体指针
type User struct {Name stringAge  int
}
u := User{"Alice", 30}
up := &u
up.Age = 31     // 等同于 (*up).Age = 31
fmt.Println(u)  // {Alice 31}// 指针作为函数参数
func increment(p *int) {*p++
}num := 5
increment(&num)
fmt.Println(num)  // 6// 返回局部变量指针(通过逃逸分析)
func newInt() *int {x := 42return &x    // 合法,x会被分配在堆上
}

多变量声明与特殊变量

多变量声明技巧

平行声明
// 声明多个同类型变量
var a, b, c int
var x, y, z = 1, 2, 3// 声明不同类型变量
var (name   = "Alice"age    = 30height = 1.65
)// 函数中多变量短声明
func process() {a, b := 10, "hello"c, d := 3.14, truefmt.Println(a, b, c, d)
}

变量交换
// 传统交换方式
a := 1
b := 2
temp := a
a = b
b = temp
fmt.Println(a, b)  // 2 1// Go特有交换方式
x := 10
y := 20
x, y = y, x  // 直接交换
fmt.Println(x, y)  // 20 10// 多值交换
i, j, k := 1, 2, 3
i, j, k = k, j, i  // i=3, j=2, k=1

分组声明
// 包级变量分组
var (count   inttotal   float64name    stringenabled bool
)// 常量分组
const (Monday = iota + 1TuesdayWednesdayThursdayFridaySaturdaySunday
)// 函数内变量分组
func process() {var (startTime time.Timeduration  time.Durationerr       error)// ...
}

空白标识符应用

忽略返回值
// 忽略文件操作中的错误
file, _ := os.Open("example.txt")
defer file.Close()// 忽略映射查找的第二个返回值
value := map[string]int{"a": 1}
v, _ := value["a"]   // 如果键存在,v=1
v, _ = value["b"]    // 如果键不存在,v=0// 忽略函数返回值
_, err := someFunction()
if err != nil {handleError(err)
}

忽略循环索引
// 忽略切片索引
names := []string{"Alice", "Bob", "Charlie"}
for _, name := range names {fmt.Println(name)
}// 忽略映射键
scores := map[string]int{"Alice": 90, "Bob": 85}
for _, score := range scores {fmt.Println(score)
}// 忽略通道索引
ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 3
close(ch)
for v := range ch {fmt.Println(v)
}

占位使用
// 类型检查
var _ io.Reader = (*MyReader)(nil)  // 确保MyReader实现了io.Reader// 导入包的副作用
import (_ "image/png"  // 注册PNG解码器"image/jpeg"   // 显式导入JPEG解码器
)// 结构体字段占位
type Config struct {_    [0]int    // 填充对齐Port int_    struct{}  // 防止未keyed字面量
}

常量与枚举

常量定义

基本用法
// 单行常量定义
const Pi = 3.141592653589793
const MaxRetry = 3
const AppName = "MyApp"// 类型化常量
const StatusOk int = 200
const Timeout time.Duration = 30 * time.Second// 常量表达式
const BufferSize = 1024 * 1024  // 1MB
const MaxUint = ^uint(0)        // 当前平台uint的最大值
const MinInt = -1 << 63        // 64位系统上int的最小值

批量声明
// 简单批量声明
const (Success = 0Failure = 1Unknown = 2
)// 使用iota的批量声明
const (Read   = 1 << iota // 1 << 0 = 1Write              // 1 << 1 = 2Execute            // 1 << 2 = 4
)// 带表达式的批量声明
const (KB = 1024MB = KB * 1024GB = MB * 1024TB = GB * 1024
)

iota枚举实践

标准枚举
// 定义枚举类型
type Weekday int// 使用iota定义枚举值
const (Sunday Weekday = iota  // 0Monday                 // 1Tuesday                // 2Wednesday              // 3Thursday               // 4Friday                 // 5Saturday               // 6
)// 使用枚举
today := Tuesday
fmt.Println(today)  // 输出: 2// 为枚举类型添加方法
func (d Weekday) String() string {return [...]string{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}[d]
}fmt.Println(today.String())  // 输出: Tuesday

位掩码枚举
// 定义权限标志
const (FlagNone = 0FlagRead = 1 << iota   // 1FlagWrite              // 2FlagExecute            // 4FlagDelete             // 8FlagAll = FlagRead | FlagWrite | FlagExecute | FlagDelete // 15
)// 使用位掩码
var permissions = FlagRead | FlagWrite  // 3// 检查权限
if permissions&FlagRead != 0 {fmt.Println("Has read permission")
}// 添加权限
permissions |= FlagExecute// 移除权限
permissions &^= FlagWrite

表达式枚举
// 基于iota的表达式枚举
const (_ = iota  // 忽略第一个值(0)KB = 1 << (10 * iota)  // 1 << (10*1) = 1024MB                     // 1 << (10*2) = 1048576GB                     // 1 << (10*3) = 1073741824TB                     // 1 << (10*4) = 1099511627776
)// 带偏移的iota
const (Low = 5 + iota  // 5Medium          // 6High            // 7Critical        // 8
)// 跳过某些值
const (A = iota  // 0B         // 1_         // 跳过2C         // 3D         // 4
)

变量与内存管理

内存优化技巧

基本类型优先
// 使用基本类型而非引用类型
// 更好:栈分配
var coords [2]float64  // 数组,值类型
coords[0] = 10.5
coords[1] = 20.3// 较差:堆分配
var coords []float64 = make([]float64, 2)  // 切片,引用类型
coords[0] = 10.5
coords[1] = 20.3// 使用固定大小数组
var buffer [256]byte  // 栈上分配
// 优于
var buffer []byte = make([]byte, 256)  // 堆上分配

对象复用
// 使用sync.Pool复用对象
var bufPool = sync.Pool{New: func() interface{} {return new(bytes.Buffer)},
}func process() {// 从池中获取Bufferbuf := bufPool.Get().(*bytes.Buffer)defer bufPool.Put(buf)  // 使用后放回池中buf.Reset()  // 重置Bufferbuf.WriteString("hello")fmt.Println(buf.String())
}// 使用局部变量缓存
func expensiveCalculation() {var cache map[string]intif cache == nil {cache = make(map[string]int)// 初始化缓存}// 使用缓存...
}

大对象处理
// 直接分配大对象(可能逃逸到堆)
var largeBuffer = make([]byte, 1<<20)  // 1MB// 分块处理更优
const chunkSize = 32 * 1024  // 32KB
var chunks [][]byte// 流式处理大文件
func processLargeFile(filename string) error {file, err := os.Open(filename)if err != nil {return err}defer file.Close()buf := make([]byte, 32*1024)  // 32KB缓冲区for {n, err := file.Read(buf)if err == io.EOF {break}if err != nil {return err}processChunk(buf[:n])}return nil
}

性能分析工具

内存分析
# 实时内存分析
go tool pprof -alloc_space http://localhost:6060/debug/pprof/heap# 生成内存profile
go test -memprofile=mem.prof -bench=.# 分析内存profile
go tool pprof -top -alloc_objects mem.prof

逃逸分析
# 查看逃逸分析结果
go build -gcflags="-m -l" main.go# 示例输出
./main.go:10:6: can inline foo
./main.go:15:6: can inline bar
./main.go:20:6: can inline main
./main.go:21:11: inlining call to foo
./main.go:22:11: inlining call to bar
./main.go:11:10: []int literal escapes to heap
./main.go:16:10: []int literal does not escape

基准测试
func BenchmarkStringConcatenation(b *testing.B) {var result stringfor i := 0; i < b.N; i++ {// 测试不同字符串拼接方式result = "Hello" + " " + "World"}_ = result
}func BenchmarkStringBuilder(b *testing.B) {var result stringfor i := 0; i < b.N; i++ {var builder strings.Builderbuilder.WriteString("Hello")builder.WriteString(" ")builder.WriteString("World")result = builder.String()}_ = result
}// 运行基准测试
// go test -bench=. -benchmem

常见问题与陷阱

典型错误案例

短声明误用
func main() {// 错误示例1:重复声明var x int// x := 10  // 编译错误:no new variables on left side// 正确做法:至少声明一个新变量x, y := 10, 20  // 正确:y是新变量// 错误示例2:短声明在包级别// z := 30  // 错误:不能在包级别使用短声明// 特殊情况下重新声明file, err := os.Open("file1.txt")// ...处理file1...// 需要重新使用err变量file, err := os.Open("file2.txt")  // 正确:file是新变量// ...处理file2...
}

作用域混淆
func printNumbers() {n := 1  // 函数级变量if true {n := 2  // 新建块级变量,遮蔽了外部的nfmt.Println(n)  // 2}fmt.Println(n)  // 1// 正确的做法:如果要修改外部nif true {n = 2  // 修改外部nfmt.Println(n)  // 2}fmt.Println(n)  // 2
}// 另一个常见问题:循环变量
func loopIssue() {var funcs []func()for i := 0; i < 3; i++ {// 错误:所有闭包共享同一个ifuncs = append(funcs, func() {fmt.Println(i)  // 全部输出3})}// 正确做法:创建局部副本for i := 0; i < 3; i++ {i := i  // 创建局部副本funcs = append(funcs, func() {fmt.Println(i)  // 输出0,1,2})}
}

零值陷阱
// 映射未初始化
var m map[string]int
// m["key"] = 1  // 运行时panic: assignment to nil map// 正确做法
m = make(map[string]int)
m["key"] = 1// 切片未初始化
var s []int
// s[0] = 1  // 运行时panic: index out of range// 正确做法
s = make([]int, 1)
s[0] = 1// 接口未初始化
var w io.Writer
// w.Write([]byte("hello"))  // 运行时panic: nil pointer dereference// 正确做法
w = os.Stdout
w.Write([]byte("hello"))

调试建议

使用vet工具
# 检查常见错误
go vet ./...# 检查特定问题
go vet -copylocks ./...
go vet -printf ./...# 集成到CI流程
# 在.gitlab-ci.yml或Jenkinsfile中添加
test:stage: testscript:- go vet ./...- go test ./...

静态分析
# 使用staticcheck进行更深入的静态分析
staticcheck ./...# 检查特定问题
staticcheck -checks "SA*" ./...  # 检查标准建议
staticcheck -checks "ST*" ./...  # 检查风格问题# 集成到开发流程
# 在pre-commit钩子中添加
#!/bin/sh
staticcheck ./...
if [ $? -ne 0 ]; thenecho "Static analysis failed"exit 1
fi

调试技巧
// 使用调试变量
var debug = os.Getenv("DEBUG") == "1"func process(data []byte) {if debug {log.Printf("Processing %d bytes", len(data))}// ...
}// 条件编译
// +build debugpackage mainvar debugMode = true// 使用runtime/debug
import "runtime/debug"func handlePanic() {if r := recover(); r != nil {debug.PrintStack()// 恢复处理...}
}// 使用pprof实时分析
import _ "net/http/pprof"func main() {go func() {log.Println(http.ListenAndServe("localhost:6060", nil))}()// 应用主逻辑...
}

最佳实践总结

声明风格

  1. 优先使用短声明(:=)

    // 函数内部优先使用短声明
    count := 0
    name := "Alice"// 仅在需要时才使用var
    var globalConfig Config  // 包级变量
    

  2. 全局变量使用var显式声明

    // 包级变量使用var
    var (maxConnections = 100timeout        = 30 * time.Second
    )
    

  3. 常量使用const声明

    // 常量使用const
    const (MaxRetries = 3DefaultPort = 8080
    )
    

命名规范

  1. 保持一致性(全项目统一风格)

    // 选择一种风格并保持一致
    var maxRetries = 3       // 小驼峰
    var ConnectionTimeout = 30 // 大驼峰导出的// 避免混合风格
    // 不要这样: var max_retries = 3
    

  2. 重要变量添加注释

    // timeoutMs specifies the maximum wait time in milliseconds
    // before aborting the request. Zero means no timeout.
    var timeoutMs = 5000// cache stores pre-computed results to improve performance.
    var cache = make(map[string]interface{})
    

  3. 避免无意义的名称

    // 不好
    var a int
    var b string
    var c []byte// 好
    var age int
    var name string
    var data []byte
    

作用域控制

  1. 最小作用域原则

    func process(data []byte) {// 仅在需要时声明变量if len(data) > 0 {first := data[0]// 使用first...}// first不可见,作用域受限
    }
    

  2. 避免不必要的全局变量

    // 不好: 不必要的全局状态
    var count intfunc increment() {count++
    }// 好: 封装状态
    type Counter struct {count int
    }func (c *Counter) Increment() {c.count++
    }
    

  3. 合理使用闭包

    func NewCounter() func() int {var count intreturn func() int {count++return count}
    }func main() {counter := NewCounter()fmt.Println(counter())  // 1fmt.Println(counter())  // 2
    }
    

http://www.dtcms.com/a/342487.html

相关文章:

  • TDengine IDMP 运维指南(管理策略)
  • CRII-Net
  • 【领码课堂】让Java数据检索更智能——Bean Searcher全景解读
  • 从”0“开始学JAVA——第九节下 泛型和集合框架
  • #运维 | 前端 # Linux http.server 实践:隐藏长文件名,简短路径 (http://IP:port/别名 ) 访问
  • AI研究引擎的简单技术实现步骤
  • Web 安全之 HTTP 响应截断攻击详解
  • JavaScript 系列之:图片压缩
  • 微信小程序设计的请求封装方案(request.js)
  • NPM模块化总结
  • DINOv3 重磅发布
  • 计算机网络技术学习-day6《三层交换机配置》
  • python发布文章和同步文章到社区的工具小脚本
  • 第三阶段数据库-6:sql中函数,多表查询,运算符,索引,约束
  • 智慧城管云平台源码,微服务vue+element+springboot+uniapp技术架构,数字化综合执法办案系统
  • 数据结构之排序大全(4)
  • 苷类成分通过 PI3K/AKT 信号通路促进内皮祖细胞来源外泌体修复受损血管内皮
  • 基于YOLO11的茶叶病害智能检测系统
  • 组态软件——工业监控“大脑”
  • leetcode-python-242有效的字母异位词
  • 代码随线录刷题Day39
  • 【uni-app】自定义导航栏以及状态栏,胶囊按钮位置信息的获取
  • Java的运行时数据区
  • Notepad++换行符替换
  • 机器学习——AdaBoost算法
  • 基于YOLO11的水稻叶片病害检测项目
  • 面试压力测试破解:如何从容应对棘手问题与挑战
  • (第二十期上)HTML 超链接标签 a
  • 【工具】前端JS/VUE修改图片分辨率
  • C语言数据结构:动态顺序表实现与应用