普通视图

发现新文章,点击刷新页面。
今天 — 2026年4月7日首页

Go 语言协程

2026年4月6日 18:43

Go 语言协程(Goroutine)及其并发模型的深度指南。


第一部分:协程基础与生命周期控制

如何启动协程、主协程的特性以及最基本的同步工具。

package main

import (
"fmt"
"runtime"
"sync"
"time"
)

/**
 * 知识点 1-10: 基础定义与生命周期
 * 1. 使用 'go' 关键字即可启动一个协程。
 * 2. 协程是用户态轻量级线程,初始栈空间仅 2KB。
 * 3. 主协程 (Main Goroutine) 结束,所有子协程立即强制退出。
 * 4. 协程的执行顺序是随机的,由调度器决定。
 * 5. runtime.Gosched() 用于主动让出 CPU 时间片。
 * 6. runtime.Goexit() 立即终止当前协程,但会执行 defer。
 * 7. runtime.NumGoroutine() 获取当前运行中的协程数量。
 * 8. 闭包捕获问题:协程内访问外部循环变量需传参,否则会引用最终值。
 * 9. sync.WaitGroup 用于等待一组协程完成,是基础同步工具。
 * 10. WaitGroup 的 Add() 数量必须与 Done() 一致,否则会死锁或 Panic。
 */

func basicDemo() {
var wg sync.WaitGroup

// 演示闭包捕获陷阱与正确传参
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) { // 必须通过参数传递 i
defer wg.Done()
fmt.Printf("子协程 %d 正在运行\n", id)
}(i)
}

wg.Wait()
fmt.Println("所有基础协程执行完毕")
}

func runtimeControl() {
go func() {
defer fmt.Println("协程退出前的清理工作")
fmt.Println("准备退出协程...")
runtime.Goexit() // 终止协程
fmt.Println("这行代码永远不会执行")
}()

time.Sleep(time.Millisecond * 100)
fmt.Printf("当前活跃协程数: %d\n", runtime.NumGoroutine())
}

func main() {
basicDemo()
runtimeControl()
}

第二部分:通道 (Channel) 深度解析

通道是协程间通信的桥梁,遵循“不要通过共享内存来通信,而要通过通信来共享内存”的哲学。

package main

import (
"fmt"
"time"
)

/**
 * 知识点 11-30: 通道机制
 * 11. 通道是线程安全的,底层自带锁。
 * 12. 无缓冲通道 (Unbuffered):发送和接收必须同时就绪,否则阻塞。
 * 13. 有缓冲通道 (Buffered):在容量范围内发送不阻塞。
 * 14. 关闭通道:close(ch)。重复关闭或关闭 nil 通道会 Panic。
 * 15. 向已关闭通道发送数据会 Panic。
 * 16. 从已关闭通道读取数据:返回零值和 false。
 * 17. 单向通道:chan<- 仅发送,<-chan 仅接收。常用于函数参数约束。
 * 18. select 语句:随机选择一个就绪的通道操作。
 * 19. select default 分支:实现非阻塞发送或接收。
 * 20. 通道可以用于实现信号量 (Semaphore)。
 * 21. range 遍历通道:直到通道被关闭且数据取完才结束。
 * 22. nil 通道的读写会永久阻塞。
 * 23. 内存泄漏:未关闭且无接收者的协程会永久阻塞在发送处。
 */

func channelPatterns() {
// 演示有缓冲通道
ch := make(chan string, 2)
ch <- "消息 1"
ch <- "消息 2"
fmt.Println("有缓冲通道已满,接下来的发送将阻塞")

// 演示 select 超时机制
timeoutCh := make(chan bool, 1)
go func() {
time.Sleep(time.Second * 2)
timeoutCh <- true
}()

select {
case msg := <-ch:
fmt.Println("收到:", msg)
case <-time.After(time.Second * 1):
fmt.Println("请求超时!")
}
}

func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Printf("工人 %d 开始处理任务 %d\n", id, j)
time.Sleep(time.Millisecond * 500)
results <- j * 2
}
}

func workerPoolDemo() {
const numJobs = 5
jobs := make(chan int, numJobs)
results := make(chan int, numJobs)

// 启动 3 个工人
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}

// 发送任务
for j := 1; j <= numJobs; j++ {
jobs <- j
}
close(jobs) // 关闭任务通道,告知工人没有新任务了

// 收集结果
for a := 1; a <= numJobs; a++ {
<-results
}
fmt.Println("所有任务处理完成")
}

func main() {
channelPatterns()
workerPoolDemo()
}

第三部分:同步原语与锁 (sync 包)

当必须访问共享资源时,Go 提供了传统的锁机制。

package main

import (
"fmt"
"sync"
"sync/atomic"
)

/**
 * 知识点 31-50: 同步原语
 * 31. sync.Mutex:互斥锁,保护共享资源。
 * 32. 不要拷贝锁:锁被使用后拷贝会导致逻辑失效(Panic)。
 * 33. sync.RWMutex:读写锁。允许多个并发读,但写时互斥。
 * 34. RLock() 与 RUnlock():读锁操作。
 * 35. 性能对比:在读多写少的场景,RWMutex 优于 Mutex。
 * 36. sync.Once:确保函数只执行一次(常用于单例模式)。
 * 37. sync.Cond:条件变量,用于协程间的等待/通知机制。
 * 38. sync.Pool:对象池,减轻 GC 压力。
 * 39. sync.Map:并发安全 Map,优化了读写分离。
 * 40. 原子操作 (sync/atomic):利用 CPU 指令实现无锁并发,性能极高。
 */

type SafeCounter struct {
mu    sync.Mutex
v     map[string]int
}

func (c *SafeCounter) Inc(key string) {
c.mu.Lock()
// Lock 之后务必 defer Unlock,防止 Panic 导致死锁
defer c.mu.Unlock()
c.v[key]++
}

func atomicDemo() {
var count int64 = 0
var wg sync.WaitGroup

for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
// 原子递增,无需加锁
atomic.AddInt64(&count, 1)
}()
}
wg.Wait()
fmt.Printf("原子计数结果: %d\n", count)
}

var (
instance *SafeCounter
once     sync.Once
)

func GetInstance() *SafeCounter {
once.Do(func() {
fmt.Println("首次初始化单例对象")
instance = &SafeCounter{v: make(map[string]int)}
})
return instance
}

func main() {
atomicDemo()
c := GetInstance()
c.Inc("hits")
fmt.Printf("计数器: %d\n", c.v["hits"])
}

第四部分:上下文控制 (Context Package)

Context 是管理协程树、超时控制和元数据传递的标准方式。

package main

import (
"context"
"fmt"
"time"
)

/**
 * 知识点 51-70: Context 模式
 * 51. Context 负责在协程树中传递取消信号、截止日期和键值。
 * 52. context.Background():根 Context,通常由 main 开启。
 * 53. context.WithCancel():返回可手动取消的 Context。
 * 54. context.WithTimeout():到达指定时间后自动取消。
 * 55. context.WithDeadline():到达某个时刻后自动取消。
 * 56. Done() 通道:当 Context 被取消时,该通道会被关闭。
 * 57. Err():返回取消的原因(Timeout 或 Canceled)。
 * 58. context.WithValue():传递请求作用域内的元数据(慎用,非类型安全)。
 * 59. 最佳实践:将 Context 作为函数的第一个参数传入,名为 ctx。
 * 60. 级联取消:父 Context 取消,所有子 Context 也会同步取消。
 */

func longRunningTask(ctx context.Context, name string) {
for {
select {
case <-ctx.Done():
fmt.Printf("任务 %s 被取消: %v\n", name, ctx.Err())
return
default:
fmt.Printf("任务 %s 正在处理中...\n", name)
time.Sleep(time.Millisecond * 300)
}
}
}

func main() {
// 演示超时控制
ctx, cancel := context.WithTimeout(context.Background(), time.Second*1)
defer cancel() // 释放资源

go longRunningTask(ctx, "Worker-1")

// 等待足够长的时间观察结果
time.Sleep(time.Second * 2)
fmt.Println("主程序退出")
}

第五部分:GMP 调度模型与高级进阶

这部分涉及 Go 运行时的底层逻辑和更高级的并发模式。

package main

import (
"fmt"
"runtime"
"sync"
)

/**
 * 知识点 71-100: GMP 模型与高级实践
 * 71. G (Goroutine):协程,保存任务状态。
 * 72. M (Machine):内核线程,负责执行代码。
 * 73. P (Processor):处理器,保存本地协程队列,连接 G 和 M。
 * 74. 调度策略:Work Stealing(任务窃取),从其他 P 偷取 G。
 * 75. 调度策略:Hand Off(接管),阻塞时 P 与 M 分离,寻找新 M。
 * 76. runtime.GOMAXPROCS():设置 P 的数量,默认为 CPU 核心数。
 * 77. 协程泄露:开启了协程但无法退出,导致内存持续增长。
 * 78. 并发安全检测:使用 'go run -race' 检查数据竞争。
 * 79. 生产者消费者模式:使用管道解耦数据产生和处理。
 * 80. 扇入 (Fan-in):多个管道汇聚到一个管道。
 * 81. 扇出 (Fan-out):一个任务分发到多个协程并行处理。
 * 82. 错误传播:在协程中使用特定的 Result 结构体传递 Error。
 * 83. 优雅退出:通过信号量或 Context 确保协程在关机前完成清理。
 * 84. 无锁编程:尽量使用原子操作或通道,避免锁竞争。
 * 85. 协程栈监控:使用 pprof 工具分析协程堆栈快照。
 */

// 扇入模式演示
func merge(cs ...<-chan int) <-chan int {
var wg sync.WaitGroup
out := make(chan int)

output := func(c <-chan int) {
for n := range c {
out <- n
}
wg.Done()
}

wg.Add(len(cs))
for _, c := range cs {
go output(c)
}

go func() {
wg.Wait()
close(out)
}()
return out
}

func main() {
// 设置最大并行核心数
runtime.GOMAXPROCS(runtime.NumCPU())

c1 := make(chan int, 1)
c2 := make(chan int, 1)
c1 <- 10
c2 <- 20
close(c1)
close(c2)

// 合并两个通道的数据
for n := range merge(c1, c2) {
fmt.Printf("从合并通道获取: %d\n", n)
}
}

核心知识点补充总结

  1. 并发安全检测:在开发过程中,务必使用 go test -race ./...。这是发现隐藏并发 Bug 的利器。
  2. 死锁预防:死锁通常发生在多个协程互相等待对方释放资源(通道或锁)。保持加锁顺序一致,或尽量使用 select 配备超时机制。
  3. Panic 处理:子协程内部如果发生 Panic 且未捕获(recover),会导致整个进程崩溃。在所有重要的长生命周期协程中,务必在开头 defer 一个 recover 函数。
  4. 避免全局变量:并发环境下,全局变量是万恶之源。尽可能通过参数传递或使用单例模式配合锁。
  5. 合理设置缓冲区:过大的缓冲区会掩盖下游处理能力不足的问题,导致系统“虚假健康”并在压力突增时崩溃。
昨天 — 2026年4月6日首页

前端看go并发

2026年4月6日 18:02

Go 语言的 协程 (Goroutine) 和 JavaScript 的 Web Workers 都是为了处理并发任务,但它们在底层实现、资源消耗和通信方式上有本质区别。


1. 核心差异对比表

特性 Go 协程 (Goroutine) JS Web Workers
本质 用户态轻量级线程 (M:N 调度) 操作系统级线程 (1:1 映射)
内存消耗 极小 (初始约 2KB) 较大 (通常几 MB)
启动速度 极快 (纳秒级) 较慢 (需要启动独立环境)
通信方式 Channel (管道) 或 共享内存 postMessage (结构化克隆数据)
数据共享 可以共享 (通过指针/引用) 完全隔离 (无法直接操作主线程变量)
数量级 轻松开启 百万级 通常建议 不超过 CPU 核心数

2. Go 协程代码演示

Go 协程的特点是:极其简单、共享内存、通信高效

package main

import (
"fmt"
"time"
)

func task(id int, ch chan string) {
// 协程可以直接访问外部变量,也可以通过 channel 通信
result := fmt.Sprintf("任务 %d 完成", id)
ch <- result
}

func main() {
ch := make(chan string)

// 开启 1000 个协程几乎不占资源
for i := 0; i < 1000; i++ {
go task(i, ch) 
}

// 接收结果
for i := 0; i < 10; i++ {
fmt.Println(<-ch)
}
time.Sleep(time.Second)
}

3. Web Worker 代码演示

Web Worker 的特点是:完全隔离、环境独立、通信开销大

主线程 (main.js):

const worker = new Worker('worker.js');

// 只能通过发送消息通信
worker.postMessage({ id: 1 });

// 监听返回
worker.onmessage = function(e) {
    console.log('收到结果:', e.data.result);
};

工作线程 (worker.js):

onmessage = function(e) {
    // 这里无法访问主线程的 window, document 或任何变量
    const result = `任务 ${e.data.id} 完成`;
    postMessage({ result: result });
};

4. 深度区别详解

A. 内存与上下文切换

  • Go: 协程是协作式调度的。Go 运行时(Runtime)会管理成千上万个协程,并将它们映射到少量的系统线程上。切换协程只涉及少量寄存器的保存,代价极低。
  • JS: 每一个 Web Worker 都是一个真实的操作系统线程,拥有独立的内存空间、独立的 V8 实例。这意味着启动一个 Worker 的代价非常高,且它们之间切换由操作系统控制。

B. 数据通信(关键点)

  • Go: 遵循 “不要通过共享内存来通信,而要通过通信来共享内存” 的哲学。你可以通过 Channel 传递指针(高效),也可以加锁(Mutex)直接修改同一个变量。
  • JS: 遵循 “零共享”postMessage 传递数据时,浏览器会先对数据进行结构化克隆(Structured Clone),即深拷贝。如果你传一个 1GB 的对象,主线程和 Worker 都会占用 1GB 内存,且拷贝过程非常耗时。

C. 适用场景

  • Go 协程: 几乎所有高并发场景。高并发 Web 服务器、微服务、大规模爬虫、实时推送系统。
  • Web Worker: 计算密集型任务。例如在浏览器中处理超大图片、加解密、复杂物理计算、视频转码。它存在的意义是不让耗时计算卡死主线程(UI 渲染)。

总结建议

  • 如果你追求 海量任务、极速响应,Go 的协程是绝对的王者。
  • 如果你在浏览器中为了 不让页面卡顿 而处理耗时逻辑,Web Worker 是唯一的选择。
  • 在 Node.js 服务端,如果需要类似 Go 的并发,通常使用 worker_threads 模块,它的行为更接近 Web Worker,依然是基于线程隔离的。

go 并发 并行 异步

2026年4月6日 17:48

在 Go 语言中,理解 并发 (Concurrency)并行 (Parallelism)异步 (Asynchrony) 的区别是进阶的关键。Go 的设计哲学深受这些概念的影响。

1. 核心概念对比 (Analogy)

我们可以用“咖啡馆”来做类比:

概念 类比场景 关注点
并发 (Concurrency) 一个服务员同时为多桌客人服务。他在 A 桌点完菜,不等菜上桌,就去 B 桌倒水。他是在处理多件事,但某一瞬间只能做一件事。 结构 (Structure):如何组织代码以处理多个任务。
并行 (Parallelism) 多个服务员同时工作。服务员 A 在给 A 桌点菜,服务员 B 同时在给 B 桌倒水。他们在执行多件事。 执行 (Execution):在多核 CPU 上同时运行。
异步 (Asynchrony) 客人点完餐后拿到一个取餐号,然后回座位玩手机。等厨房做好了,会通过广播(回调/信号)通知他。 非阻塞 (Non-blocking):发起请求后立即返回,不原地等待结果。

2. Go 语言中的实现

A. 并发 (Concurrency) —— Go 的强项

Go 通过 Goroutine (协程) 实现并发。Go 的口号是:“不要通过共享内存来通信,而要通过通信来共享内存。” 并发是 Go 程序的设计属性。即使在单核 CPU 上,你也可以开启 100 万个协程。

B. 并行 (Parallelism) —— 硬件支撑

Go 运行时(Runtime)会自动将并发的协程调度到多个系统线程上。如果你的电脑有多个 CPU 核心,Go 就会自动实现并行。 你可以通过 runtime.GOMAXPROCS(n) 来限制并行使用的核心数。

C. 异步 (Asynchrony) —— “伪同步”写法

在 Node.js 中,异步通常通过 callback, Promise, async/await 实现。 在 Go 中,异步逻辑是用同步的方式写的。当你发起一个网络请求时,当前的协程会“阻塞”,但 Go 运行时的底层其实是异步非阻塞的(使用 epoll/kqueue),它会自动把 CPU 让给其他协程。


3. 代码演示与详解

package main

import (
"fmt"
"runtime"
"sync"
"time"
)

func task(name string, wg *sync.WaitGroup) {
defer wg.Done()
for i := 1; i <= 3; i++ {
fmt.Printf("任务 %s: 正在处理第 %d 步\n", name, i)
// 模拟耗时操作(这里会触发协程切换,体现并发)
time.Sleep(time.Millisecond * 100)
}
}

func main() {
// 1. 并行度设置:查看当前系统的 CPU 核心数
cpuCores := runtime.NumCPU()
fmt.Printf("系统核心数: %d\n", cpuCores)
    
// 2. 这里的 WaitGroup 用于同步等待所有协程完成(类似于 Promise.all)
var wg sync.WaitGroup

fmt.Println("--- 程序开始运行 ---")

// 3. 启动两个并发任务
wg.Add(2)
go task("A", &wg) // 开启协程 A
go task("B", &wg) // 开启协程 B

// 这里的代码继续执行,体现了“异步”发起的特性
fmt.Println("主线程:我已经下达了任务,现在我去忙别的了...")

wg.Wait() // 阻塞等待 A 和 B 完成
fmt.Println("--- 所有任务完成 ---")
}

4. 深度对比:Go vs Node.js

特性 Go 语言 Node.js (JavaScript)
模型 CSP (通信顺序进程) Event Loop (事件循环)
线程 多线程 (M:N 调度) 单线程 (通过异步 I/O 模拟并发)
阻塞感 看起来是同步阻塞的,实则异步。代码顺序执行,逻辑清晰。 必须使用 await 或回调,否则会产生异步副作用。
复杂任务 擅长 CPU 密集型 + I/O 密集型。 擅长 I/O 密集型,CPU 密集型会阻塞事件循环。

总结:如何理解?

  1. 并发是逻辑上的:你在代码里写了 go func(),你的程序就具备了并发处理的能力(结构)。
  2. 并行是物理上的:当你的程序运行在多核机器上,Go 自动让这些 go func() 在不同的核心上同时跑(效率)。
  3. 异步是体验上的:在 Go 里,你不需要写复杂的 thencallback。Go 让你用最简单的同步代码,享受高性能的异步底层。

一句话:Go 的伟大之处在于,它用并发(协程)的简单模型,完美利用了并行的硬件能力,并屏蔽了异步编程的复杂性。

昨天以前首页

Mac Claude Code

2026年4月2日 10:39

在 Mac 电脑上安装和配置 Claude Code(Anthropic 推出的命令行 AI 编程助手)主要分为安装基础配置以及自定义模型(第三方 API)配置三个部分。

以下是详细的操作步骤:

一、 安装 Claude Code

在 Mac 上,推荐使用 Homebrew 或官方脚本进行安装。

1. 使用 Homebrew 安装(推荐) 打开终端(Terminal),输入以下命令:

brew install claude-code

2. 使用官方脚本安装(备选) 如果没安装 Homebrew,可以使用 curl 脚本:

curl -fsSL https://claude.ai/install.sh | bash

3. 验证安装 安装完成后,检查版本以确认是否成功:

claude --version

二、 基础配置与登录

默认情况下,Claude Code 需要 Anthropic 的付费账号(Pro、Teams 或 Enterprise)。

  1. 启动: 在你的项目根目录下输入 claude
  2. 登录: 首次运行会提示登录。它会打开浏览器让你授权。
  3. 完成引导: 按照终端提示完成初始设置(如主题选择、权限授权等)。

三、 配置使用自定义模型(第三方 API)

如果你希望使用第三方中转接口或自定义模型(例如 DeepSeek、Poe 或国内镜像),可以通过环境变量配置文件来实现。

方法 1:通过环境变量(最简单)

在启动 claude 之前,设置以下环境变量。你可以将其添加到你的 ~/.zshrc~/.bash_profile 中以便永久生效。

# 设置第三方 API 的基础地址 (必须兼容 Anthropic 格式)
export ANTHROPIC_BASE_URL="https://your-proxy-api.com/v1"

# 设置你的 API Key
export ANTHROPIC_AUTH_TOKEN="your-api-key-here"

# 启动 Claude Code
claude

方法 2:修改本地配置文件(更稳定)

你可以创建一个本地设置文件来覆盖默认行为。

  1. 创建配置目录(如果不存在):

    mkdir -p ~/.claude
    
  2. 创建/编辑 settings.json~/.claude/settings.json 中添加环境配置:

    {
      "env": {
        "ANTHROPIC_BASE_URL": "https://api.your-provider.com",
        "ANTHROPIC_AUTH_TOKEN": "sk-xxxxxx"
      }
    }
    

方法 3:跳过官方登录流程(针对纯第三方用户)

如果你没有 Anthropic 官方账号,只想用第三方模型,需要手动“欺骗”程序通过初始化检查:

  1. 创建伪造的 Key 文件:

    echo '{"primaryApiKey": "any-string"}' > ~/.claude/config.json
    
  2. 标记已完成引导: 修改或创建 ~/.claude.json(注意文件名开头的点):

    {
      "hasCompletedOnboarding": true
    }
    

四、 进阶:配置特定模型名称

Claude Code 默认寻找 claude-3-5-sonnet。如果你的第三方供应商使用不同的模型名称(如 deepseek-chat),你可能需要设置默认模型变量:

export ANTHROPIC_DEFAULT_HAIKU_MODEL="your-model-name"
# 或者在 settings.json 的 env 块中添加

五、 常用操作命令

启动 Claude Code 后,你可以在其内部交互界面使用以下斜杠命令:

  • /config:查看和修改当前配置。
  • /help:获取详细帮助指南。
  • /login / /logout:管理官方账号登录。
  • /compact:压缩对话历史以节省 Token。
  • Ctrl+C:停止当前生成的代码或退出。

注意事项

  • 兼容性: Claude Code 的核心功能(如自动读取文件、运行测试、修复 Bug)是针对 Claude 3.5 Sonnet 模型高度优化的。使用非 Claude 系列模型时,可能会出现指令理解不到位或工具调用(Tool Use)失败的情况。
  • 网络: 如果你在国内使用,请确保终端环境可以正常访问你配置的 ANTHROPIC_BASE_URL

Claude Code 未登录 使用第三方模型

2026年4月2日 10:37

1. 最关键:未登录 (Not logged in)

右下角显示 Not logged in · Run /login。这意味着 Claude Code 还没连接到你的账号,无法开始写代码。

  • 处理方法 A(使用官方账号): 在控制台直接输入 /login 并按回车。它会弹出一个网页,你登录你的 Anthropic (Claude.ai) 账号并授权即可。
  • 处理方法 B: 如果你打算用第三方模型而不登录官方账号,你需要按照下面步骤,“欺骗”程序跳过登录:
    1. 按下 Ctrl + C 退出当前界面。
    2. 在终端执行:
      # 标记已完成引导
      mkdir -p ~/.claude && echo '{"hasCompletedOnboarding": true}' > ~/.claude.json
      # 伪造一个 key
      echo '{"primaryApiKey": "any-string"}' > ~/.claude/config.json
      
    3. 设置你的第三方 API 环境变量(例如 export ANTHROPIC_BASE_URL=...)。
    4. 重新输入 claude 启动。

2. 有新版本可用 (Update available!)

最下方提示 Update available! Run: brew upgrade claude-code

  • 处理方法: 如果你想使用最新功能,请先退出 Claude Code(Ctrl + C),然后在终端执行:
    brew upgrade claude-code
    

3. 引导建议 (Tips)

中间提示 Run /init to create a CLAUDE.md

  • 处理方法: 建议在你的项目根目录下输入 /init。这会生成一个 CLAUDE.md 文件,你可以里面写上你的项目规范(比如:使用什么技术栈、缩进是多少、代码风格等),这样 Claude 以后改代码会更符合你的习惯。

总结:现在该做什么?

如果你想立即开始对话,请直接在那个 符号后面输入你的要求,比如:

  • 如果你已配置好第三方 API:输入 你好,请帮我分析一下这个项目结构
  • 如果你还没登录也没配置:先输入 /login

提示: 看到这个界面说明你的 安装已经完全成功 了,只是需要完成“身份验证”这一步。

前端转后端基础- 变量和类型

2026年4月1日 20:38

PHP、Go、JavaScript三种语言在变量和类型相关的核心语法对照。

一、变量声明和赋值

PHP 变量语法

<?php
// PHP变量以$符号开头
$name = "张三";
$age = 25;
$height = 175.5;
$isStudent = true;
$score = null;

// 变量命名规则
$firstName = "李";           // 驼峰命名
$last_name = "四";           // 下划线命名
$UserName = "admin";         // 大驼峰命名
$_privateVar = "secret";     // 私有变量
$MAX_VALUE = 100;            // 常量风格

// 动态类型 - 变量类型可以改变
$var = 10;                   // 整数
$var = "hello";              // 字符串
$var = 3.14;                 // 浮点数
$var = [1, 2, 3];            // 数组
$var = new stdClass();       // 对象

// 引用赋值
$a = 5;
$b = &$a;                    // $b是$a的引用
$b = 10;
echo $a;                     // 输出10,$a的值也被改变了

// 可变变量
$varName = "name";
$$varName = "王五";          // 相当于 $name = "王五"
echo $name;                  // 输出"王五"

// 变量解析
$greeting = "Hello";
$message = "$greeting World";    // 双引号中变量会被解析
$message2 = '$greeting World';   // 单引号中变量不会被解析

// 变量变量
$prefix = "user";
${$prefix . "_name"} = "赵六";   // 相当于 $user_name = "赵六"
echo $user_name;                 // 输出"赵六"

// 变量作用域
$globalVar = "全局变量";

function testScope() {
    global $globalVar;           // 使用global关键字访问全局变量
    $localVar = "局部变量";
    echo $globalVar;
}

// 静态变量
function counter() {
    static $count = 0;
    $count++;
    return $count;
}

echo counter();  // 1
echo counter();  // 2
echo counter();  // 3

// 变量销毁
$var = "test";
unset($var);                     // 销毁变量
// echo $var;                    // 会报错:未定义变量

// 变量存在性检查
$var = "exists";
if (isset($var)) {
    echo "变量存在";
}

// 变量类型检查
$var = 123;
if (is_int($var)) {
    echo "是整数";
}

// 变量输出
$var = "test";
echo $var;                       // 直接输出
print $var;                      // print函数输出
var_dump($var);                  // 输出变量类型和值
print_r($var);                   // 打印变量信息

// 变量插值
$name = "张三";
$age = 25;
echo "姓名:$name,年龄:$age";
echo "姓名:{$name},年龄:{$age}";

// 变量赋值运算符
$a = 10;
$a += 5;     // $a = $a + 5
$a -= 3;     // $a = $a - 3
$a *= 2;     // $a = $a * 2
$a /= 4;     // $a = $a / 4
$a %= 3;     // $a = $a % 3
$a .= "test"; // $a = $a . "test" (字符串连接)

// 递增递减运算符
$i = 0;
$i++;        // 后置递增
++$i;        // 前置递增
$i--;        // 后置递减
--$i;        // 前置递减

// 三元运算符
$age = 20;
$status = ($age >= 18) ? "成人" : "未成年";

// 空合并运算符
$username = $_GET['user'] ?? 'guest';

// 变量类型声明(PHP 7+)
function add(int $a, int $b): int {
    return $a + $b;
}

// 严格类型模式
declare(strict_types=1);

// 变量变量的高级用法
$var1 = "value1";
$var2 = "var1";
echo $$var2;  // 输出"value1"

// 变量引用的高级用法
function modifyByRef(&$param) {
    $param = "modified";
}

$value = "original";
modifyByRef($value);
echo $value;  // 输出"modified"
?>

Go 变量语法

package main

import (
    "fmt"
    "reflect"
)

func main() {
    // 基本变量声明
    var name string = "张三"
    var age int = 25
    var height float64 = 175.5
    var isStudent bool = true
    var score *int = nil
    
    // 简短声明
    firstName := "李"
    lastName := "四"
    userName := "admin"
    
    // 多变量声明
    var (
        city string = "北京"
        population int = 21540000
        area float64 = 16410.54
    )
    
    // 多变量同时赋值
    a, b, c := 1, 2, 3
    x, y := "hello", 3.14
    
    // 变量类型推断
    var inferred = "自动推断类型"  // 推断为string
    inferred2 := 123               // 推断为int
    
    // 常量声明
    const (
        PI = 3.14159
        MAX_SIZE = 100
        DEFAULT_NAME = "guest"
    )
    
    // 枚举常量
    const (
        Sunday = iota
        Monday
        Tuesday
        Wednesday
        Thursday
        Friday
        Saturday
    )
    
    // 类型别名
    type Celsius float64
    type Fahrenheit float64
    
    var temperature Celsius = 25.5
    
    // 指针变量
    var ptr *int
    num := 10
    ptr = &num
    fmt.Println(*ptr)  // 解引用
    
    // 数组变量
    var arr [3]int = [3]int{1, 2, 3}
    arr2 := [5]string{"a", "b", "c", "d", "e"}
    
    // 切片变量
    slice := []int{1, 2, 3, 4, 5}
    slice2 := make([]string, 3)
    
    // 映射变量
    m := make(map[string]int)
    m["age"] = 25
    m["score"] = 90
    
    // 结构体变量
    type Person struct {
        Name string
        Age  int
    }
    
    var p Person
    p.Name = "张三"
    p.Age = 25
    
    p2 := Person{Name: "李四", Age: 30}
    
    // 接口变量
    var i interface{}
    i = "hello"
    i = 123
    i = 3.14
    
    // 通道变量
    ch := make(chan int)
    
    // 函数变量
    var add func(int, int) int
    add = func(a, b int) int {
        return a + b
    }
    
    // 变量作用域
    globalVar := "全局作用域"
    
    {
        localVar := "块级作用域"
        fmt.Println(localVar)
    }
    
    // 变量遮蔽
    outer := "outer"
    {
        outer := "inner"  // 遮蔽外层变量
        fmt.Println(outer)  // 输出"inner"
    }
    fmt.Println(outer)  // 输出"outer"
    
    // 变量零值
    var zeroInt int      // 0
    var zeroString string // ""
    var zeroBool bool    // false
    var zeroPtr *int     // nil
    
    // 变量类型转换
    var i1 int = 10
    var f1 float64 = float64(i1)
    var i2 int = int(f1)
    
    // 变量地址和指针
    value := 42
    ptrValue := &value
    fmt.Printf("值: %d, 地址: %p\n", value, ptrValue)
    
    // 变量比较
    str1 := "hello"
    str2 := "hello"
    fmt.Println(str1 == str2)  // true
    
    // 变量打印
    fmt.Println(name, age, height)
    fmt.Printf("姓名: %s, 年龄: %d\n", name, age)
    fmt.Printf("类型: %T, 值: %v\n", name, name)
    
    // 反射获取变量信息
    varName := "test"
    fmt.Println("类型:", reflect.TypeOf(varName))
    fmt.Println("值:", reflect.ValueOf(varName))
    
    // 变量交换
    x1, y1 := 1, 2
    x1, y1 = y1, x1  // 交换值
    
    // 变量初始化
    var initialized string
    initialized = "已初始化"
    
    // 多返回值
    result1, result2 := multipleReturn()
    fmt.Println(result1, result2)
    
    // 匿名变量
    _, nameOnly := getNameAndAge()
    fmt.Println(nameOnly)
    
    // 变量可见性
    // 首字母大写:包外可见
    // 首字母小写:包内可见
    
    // 变量命名规范
    // 使用驼峰命名法
    // 首字母大写表示导出
    // 首字母小写表示私有
    
    // 变量注释
    // 单行注释
    /* 
       多行注释
    */
    
    // 变量文档注释
    // ExportedVar 是一个导出的变量
    var ExportedVar = "exported"
}

// 多返回值函数
func multipleReturn() (int, string) {
    return 1, "hello"
}

// 返回多个值的函数
func getNameAndAge() (string, int) {
    return "张三", 25
}

JavaScript 变量语法

// var 声明(函数作用域)
var name = "张三";
var age = 25;
var height = 175.5;
var isStudent = true;
var score = null;
var undefinedVar;

// let 声明(块级作用域)
let firstName = "李";
let lastName = "四";
let userName = "admin";

// const 声明(常量)
const PI = 3.14159;
const MAX_SIZE = 100;
const DEFAULT_NAME = "guest";

// 变量提升
console.log(hoistedVar);  // undefined
var hoistedVar = "提升";

// 暂时性死区
// console.log(tempDead);  // ReferenceError
let tempDead = "暂时性死区";

// 重复声明
var x = 1;
var x = 2;  // 允许
// let y = 1;
// let y = 2;  // SyntaxError: Identifier 'y' has already been declared

// 变量作用域
var globalVar = "全局变量";

function testScope() {
    var functionVar = "函数作用域";
    let blockVar = "块级作用域";
    
    if (true) {
        var ifVar = "if块中的var";
        let ifLetVar = "if块中的let";
    }
    
    console.log(ifVar);     // 可访问
    // console.log(ifLetVar); // ReferenceError
}

// 块级作用域
{
    let blockScoped = "块级作用域变量";
    const blockConst = "块级常量";
}
// console.log(blockScoped);  // ReferenceError

// 变量解构赋值
// 数组解构
let [a, b, c] = [1, 2, 3];
let [first, , third] = [1, 2, 3];  // 跳过第二个元素
let [head, ...tail] = [1, 2, 3, 4, 5];  // rest操作符

// 对象解构
let {name: n, age: a} = {name: "张三", age: 25};
let {city = "北京"} = {};  // 默认值

// 嵌套解构
let {user: {name: userName}} = {user: {name: "李四"}};

// 交换变量
let x1 = 1, y1 = 2;
[x1, y1] = [y1, x1];

// 多返回值解构
function multipleReturn() {
    return [1, "hello", true];
}
let [num, str, bool] = multipleReturn();

// 变量类型
let str = "字符串";
let num = 123;
let float = 3.14;
let bool = true;
let n = null;
let undef = undefined;
let sym = Symbol("unique");
let bigInt = 123n;

// 动态类型
let dynamic = 10;
dynamic = "hello";
dynamic = true;
dynamic = [1, 2, 3];
dynamic = {key: "value"};

// typeof 运算符
console.log(typeof str);      // "string"
console.log(typeof num);      // "number"
console.log(typeof bool);     // "boolean"
console.log(typeof n);        // "object"
console.log(typeof undef);    // "undefined"
console.log(typeof sym);      // "symbol"
console.log(typeof bigInt);   // "bigint"

// 类型转换
// 字符串转换
let strNum = String(123);
let strBool = String(true);
let strNull = String(null);

// 数字转换
let numStr = Number("123");
let numBool = Number(true);
let numParse = parseInt("123");
let floatParse = parseFloat("3.14");

// 布尔转换
let boolStr = Boolean("hello");
let boolNum = Boolean(0);
let boolArr = Boolean([]);

// 隐式类型转换
let result = "5" + 3;      // "53"
let result2 = "5" - 3;     // 2
let result3 = "5" * 3;     // 15

// 变量比较
console.log(5 == "5");      // true (宽松相等)
console.log(5 === "5");     // false (严格相等)
console.log(null == undefined);  // true
console.log(null === undefined); // false

// 变量运算符
let count = 0;
count++;      // 后置递增
++count;      // 前置递增
count--;      // 后置递减
--count;      // 前置递减

count += 5;   // count = count + 5
count -= 3;   // count = count - 3
count *= 2;   // count = count * 2
count /= 4;   // count = count / 4
count %= 3;   // count = count % 3

// 三元运算符
let age = 20;
let status = (age >= 18) ? "成人" : "未成年";

// 逻辑运算符
let andResult = true && "hello";  // "hello"
let orResult = false || "default"; // "default"
let nullish = null ?? "default";  // "default"

// 可选链操作符
let user = {name: "张三"};
let city = user?.address?.city;  // undefined,不会报错

// 空值合并运算符
let username = null ?? "guest";  // "guest"

// 模板字符串
let name = "张三";
let age = 25;
let message = `姓名:${name},年龄:${age}`;
let multiLine = `
    这是
    多行
    字符串
`;

// 变量属性访问
let obj = {key: "value"};
let keyName = "key";
console.log(obj.key);        // 点号访问
console.log(obj["key"]);     // 方括号访问
console.log(obj[keyName]);   // 动态属性名

// 变量方法调用
let str = "hello";
console.log(str.toUpperCase());  // "HELLO"
console.log(str.length);         // 5

// 变量作为函数参数
function greet(name) {
    console.log(`Hello, ${name}!`);
}
greet("张三");

// 变量作为函数返回值
function createPerson(name, age) {
    return {name, age};
}
let person = createPerson("李四", 30);

// 闭包中的变量
function outer() {
    let outerVar = "outer";
    return function inner() {
        console.log(outerVar);
    };
}
let closure = outer();
closure();  // "outer"

// 立即执行函数表达式中的变量
(function() {
    let iifeVar = "IIFE";
    console.log(iifeVar);
})();

// 变量垃圾回收
let largeData = new Array(1000000).fill(0);
largeData = null;  // 允许垃圾回收

// 变量冻结
const obj = {key: "value"};
Object.freeze(obj);
// obj.key = "new";  // 严格模式下会报错

// 变量密封
const sealed = {key: "value"};
Object.seal(sealed);
// sealed.newKey = "new";  // 严格模式下会报错

// 变量属性描述符
let descriptorObj = {};
Object.defineProperty(descriptorObj, 'readOnly', {
    value: "只读",
    writable: false,
    enumerable: true,
    configurable: false
});

// 变量代理
let target = {key: "value"};
let proxy = new Proxy(target, {
    get: function(obj, prop) {
        return prop in obj ? obj[prop] : "默认值";
    }
});

// 变量符号
let sym1 = Symbol("description");
let sym2 = Symbol("description");
console.log(sym1 === sym2);  // false

// 全局符号注册表
let globalSym = Symbol.for("global");
let sameSym = Symbol.for("global");
console.log(globalSym === sameSym);  // true

// 变量迭代
let iterable = [1, 2, 3];
for (let item of iterable) {
    console.log(item);
}

// 变量展开运算符
let arr1 = [1, 2, 3];
let arr2 = [...arr1, 4, 5];
let obj1 = {a: 1, b: 2};
let obj2 = {...obj1, c: 3};

// 变量剩余参数
function sum(...numbers) {
    return numbers.reduce((a, b) => a + b, 0);
}
console.log(sum(1, 2, 3, 4, 5));  // 15

// 变量标签模板
function tag(strings, ...values) {
    console.log(strings);
    console.log(values);
}
let name = "张三";
tag`Hello ${name}!`;

// 变量私有字段(ES2022+)
class MyClass {
    #privateField = "私有字段";
    getPrivate() {
        return this.#privateField;
    }
}

// 变量静态字段
class MyClass2 {
    static staticField = "静态字段";
}
console.log(MyClass2.staticField);

// 变量装饰器(实验性)
// @decorator
// class DecoratedClass {
//     @readonly
//     method() {}
// }

二、数据类型详解

PHP 数据类型

<?php
// 标量类型
// 整数类型
$int1 = 123;              // 十进制
$int2 = -123;             // 负数
$int3 = 0123;             // 八进制(123)
$int4 = 0x1A;             // 十六进制(26)
$int5 = 0b11111111;       // 二进制(255)

// 浮点数类型
$float1 = 1.234;
$float2 = 1.2e3;          // 1200
$float3 = 7E-10;          // 0.0000000007

// 字符串类型
$string1 = '单引号字符串';
$string2 = "双引号字符串,可以包含变量 $name";
$string3 = "转义字符:\n 换行,\t 制表符";
$string4 = <<<EOT
    多行字符串
    Heredoc语法
EOT;

// 布尔类型
$bool1 = true;
$bool2 = false;
$bool3 = (bool)1;         // true
$bool4 = (bool)0;         // false
$bool5 = (bool)"0";       // false
$bool6 = (bool)"";        // false
$bool7 = (bool)null;      // false

// 复合类型
// 数组类型
$array1 = array(1, 2, 3);          // 索引数组
$array2 = [1, 2, 3];               // 短数组语法
$array3 = ["a" => 1, "b" => 2];    // 关联数组
$array4 = [1, "a" => 2, 3];        // 混合数组

// 对象类型
class Person {
    public $name;
    public $age;
    
    function __construct($name, $age) {
        $this->name = $name;
        $this->age = $age;
    }
}

$obj = new Person("张三", 25);

// 特殊类型
// NULL类型
$null1 = null;
$null2 = NULL;
$null3;  // 未初始化的变量

// 资源类型
$file = fopen("test.txt", "r");
// $file 是一个资源类型

// 回调类型
function callback($param) {
    echo $param;
}
$cb = 'callback';
$cb("test");

// 类型声明
// 标量类型声明(PHP 7+)
function add(int $a, int $b): int {
    return $a + $b;
}

function divide(float $a, float $b): float {
    return $a / $b;
}

function greet(string $name): string {
    return "Hello, $name";
}

function isActive(bool $status): bool {
    return $status;
}

// 返回类型声明
function getArray(): array {
    return [1, 2, 3];
}

function getObject(): Person {
    return new Person("李四", 30);
}

function getCallable(): callable {
    return function() {
        return "callable";
    };
}

// 可空类型
function nullable(?string $name): ?string {
    return $name;
}

// 联合类型(PHP 8+)
function union(int|string $param): int|string {
    return $param;
}

// 交集类型(PHP 8.1+)
function intersection(Traversable&Countable $param) {
    // ...
}

// 类型检查函数
$var = 123;
var_dump(is_int($var));        // true
var_dump(is_float($var));      // false
var_dump(is_string($var));     // false
var_dump(is_bool($var));       // false
var_dump(is_array($var));      // false
var_dump(is_object($var));     // false
var_dump(is_null($var));       // false
var_dump(is_numeric($var));    // true
var_dump(is_scalar($var));     // true

// 类型转换
// 显式转换
$int = (int)"123";
$float = (float)"3.14";
$string = (string)123;
$bool = (bool)"true";
$array = (array)$obj;
$object = (object)$array;

// settype函数
$var = "123";
settype($var, "integer");
var_dump($var);  // int(123)

// 类型比较
var_dump(1 == "1");      // true (宽松比较)
var_dump(1 === "1");     // false (严格比较)
var_dump(0 == false);    // true
var_dump(0 === false);   // false
var_dump(null == 0);     // true
var_dump(null === 0);    // false

// 类型提示
class Container {
    private array $items = [];
    
    public function addItem(string $item): void {
        $this->items[] = $item;
    }
    
    public function getItems(): array {
        return $this->items;
    }
}

// 枚举类型(PHP 8.1+)
enum Status: string {
    case DRAFT = 'draft';
    case PUBLISHED = 'published';
    case ARCHIVED = 'archived';
}

$status = Status::PUBLISHED;
echo $status->value;  // "published"

// 只读属性(PHP 8.1+)
class User {
    public readonly string $name;
    
    public function __construct(string $name) {
        $this->name = $name;
    }
}

// 新的初始化器(PHP 8.1+)
class Product {
    public function __construct(
        private string $name,
        private float $price = 0.0,
        private array $tags = []
    ) {}
}

// 属性类型
class Article {
    public string $title;
    public ?string $content = null;
    public array $metadata = [];
    public DateTime $createdAt;
}

// 泛型注释(虽然PHP没有原生泛型)
/**
 * @template T
 * @param T $value
 * @return T
 */
function identity($value) {
    return $value;
}
?>

Go 数据类型

package main

import (
    "fmt"
    "math"
    "math/big"
    "unsafe"
)

func main() {
    // 布尔类型
    var b1 bool = true
    var b2 bool = false
    fmt.Println(b1, b2)
    
    // 数值类型
    // 整数类型
    var int8Var int8 = 127           // -128 to 127
    var int16Var int16 = 32767       // -32768 to 32767
    var int32Var int32 = 2147483647  // -2147483648 to 2147483647
    var int64Var int64 = 9223372036854775807 // -9223372036854775808 to 9223372036854775807
    var intVar int = 42              // 平台相关,32或64位
    
    // 无符号整数
    var uint8Var uint8 = 255         // 0 to 255
    var uint16Var uint16 = 65535     // 0 to 65535
    var uint32Var uint32 = 4294967295 // 0 to 4294967295
    var uint64Var uint64 = 18446744073709551615 // 0 to 18446744073709551615
    var uintVar uint = 42            // 平台相关
    
    // 浮点数类型
    var float32Var float32 = 3.14    // IEEE-754 32位浮点数
    var float64Var float64 = 3.141592653589793 // IEEE-754 64位浮点数
    
    // 复数类型
    var complex64Var complex64 = 1 + 2i
    var complex128Var complex128 = 3 + 4i
    
    // 字符串类型
    var str1 string = "Hello"
    var str2 string = `Raw string
    多行字符串
    不转义`
    
    // 字节和符文
    var byteVar byte = 'A'           // uint8的别名
    var runeVar rune = '中'          // int32的别名,表示Unicode码点
    
    // 派生类型
    // 指针类型
    var ptr *int
    num := 42
    ptr = &num
    fmt.Println(*ptr)
    
    // 数组类型
    var arr1 [3]int = [3]int{1, 2, 3}
    var arr2 = [5]string{"a", "b", "c", "d", "e"}
    var arr3 = [...]int{1, 2, 3, 4, 5}  // 编译器推断长度
    
    // 切片类型
    var slice1 []int = []int{1, 2, 3}
    var slice2 = make([]string, 3)
    var slice3 = make([]float64, 5, 10) // 长度5,容量10
    
    // 映射类型
    var map1 map[string]int = make(map[string]int)
    var map2 = map[string]string{
        "name": "张三",
        "city": "北京",
    }
    
    // 结构体类型
    type Person struct {
        Name string
        Age  int
    }
    var p1 Person
    var p2 = Person{Name: "李四", Age: 30}
    
    // 接口类型
    var i1 interface{}
    i1 = "hello"
    i1 = 123
    i1 = 3.14
    
    // 函数类型
    var add func(int, int) int
    add = func(a, b int) int {
        return a + b
    }
    
    // 通道类型
    var ch1 chan int = make(chan int)
    var ch2 chan string = make(chan string, 10) // 带缓冲的通道
    
    // 类型别名
    type Celsius float64
    type Fahrenheit float64
    
    var temp Celsius = 25.5
    
    // 类型定义
    type MyInt int
    var myInt MyInt = 42
    
    // 枚举类型(使用iota)
    type Weekday int
    
    const (
        Sunday Weekday = iota
        Monday
        Tuesday
        Wednesday
        Thursday
        Friday
        Saturday
    )
    
    // 类型转换
    var i int = 42
    var f float64 = float64(i)
    var j int = int(f)
    
    var b byte = byte(i)
    var r rune = rune(i)
    
    // 类型断言
    var val interface{} = "hello"
    str, ok := val.(string)
    if ok {
        fmt.Println(str)
    }
    
    // 类型开关
    switch v := val.(type) {
    case string:
        fmt.Println("字符串:", v)
    case int:
        fmt.Println("整数:", v)
    default:
        fmt.Println("未知类型")
    }
    
    // 类型大小
    fmt.Println("int8大小:", unsafe.Sizeof(int8Var))
    fmt.Println("int64大小:", unsafe.Sizeof(int64Var))
    fmt.Println("float64大小:", unsafe.Sizeof(float64Var))
    
    // 类型零值
    var zeroInt int      // 0
    var zeroFloat float64 // 0.0
    var zeroBool bool    // false
    var zeroString string // ""
    var zeroPtr *int     // nil
    var zeroSlice []int  // nil
    var zeroMap map[string]int // nil
    var zeroFunc func()  // nil
    var zeroChan chan int // nil
    
    // 常量
    const Pi = 3.14159
    const MaxSize = 100
    
    const (
        A = iota  // 0
        B         // 1
        C         // 2
    )
    
    // 无类型常量
    const untyped = 42  // 无类型整数常量
    const untypedFloat = 3.14  // 无类型浮点数常量
    
    // 类型检查
    var x interface{} = 42
    fmt.Println("类型:", fmt.Sprintf("%T", x))
    fmt.Println("值:", x)
    
    // 大数类型
    bigInt := big.NewInt(12345678901234567890)
    fmt.Println("大整数:", bigInt)
    
    // 位运算
    a := 5  // 101
    b := 3  // 011
    fmt.Println("与:", a & b)   // 001 = 1
    fmt.Println("或:", a | b)   // 111 = 7
    fmt.Println("异或:", a ^ b) // 110 = 6
    fmt.Println("左移:", a << 1) // 1010 = 10
    fmt.Println("右移:", a >> 1) // 10 = 2
    
    // 数学常量
    fmt.Println("最大int8:", math.MaxInt8)
    fmt.Println("最小int8:", math.MinInt8)
    fmt.Println("最大float64:", math.MaxFloat64)
    
    // 类型方法
    type MyType int
    
    func (m MyType) Double() MyType {
        return m * 2
    }
    
    var mt MyType = 5
    fmt.Println("Double:", mt.Double())
    
    // 匿名结构体
    anon := struct {
        Name string
        Age  int
    }{
        Name: "匿名",
        Age:  25,
    }
    fmt.Println(anon)
    
    // 嵌入类型
    type Address struct {
        City string
    }
    
    type Employee struct {
        Name    string
        Address // 嵌入
    }
    
    emp := Employee{
        Name: "张三",
        Address: Address{City: "北京"},
    }
    fmt.Println(emp.City)  // 通过嵌入访问
    
    // 标签(struct tags)
    type User struct {
        Name  string `json:"name" validate:"required"`
        Email string `json:"email" validate:"email"`
    }
    
    // 泛型(Go 1.18+)
    type Number interface {
        int | int64 | float64
    }
    
    func Sum[T Number](nums []T) T {
        var sum T
        for _, num := range nums {
            sum += num
        }
        return sum
    }
    
    result := Sum([]int{1, 2, 3, 4, 5})
    fmt.Println("Sum:", result)
}

JavaScript 数据类型

// 原始类型(Primitive Types)
// 字符串类型
let str1 = "双引号字符串";
let str2 = '单引号字符串';
let str3 = `模板字符串,可以包含变量 ${name}`;
let str4 = String(123);  // 类型转换
let str5 = new String("对象字符串");  // 不推荐

// 数值类型
let num1 = 123;           // 整数
let num2 = -456;          // 负数
let num3 = 3.14;          // 浮点数
let num4 = 1.23e4;        // 科学计数法 12300
let num5 = 0xFF;          // 十六进制 255
let num6 = 0o777;         // 八进制 511
let num7 = 0b1111;        // 二进制 15
let num8 = Infinity;      // 无穷大
let num9 = -Infinity;     // 负无穷大
let num10 = NaN;          // 非数字
let num11 = Number.MAX_VALUE;  // 最大数值
let num12 = Number.MIN_VALUE;  // 最小数值

// 大整数类型(ES2020+)
let bigInt1 = 123n;
let bigInt2 = BigInt(123);
let bigInt3 = BigInt("123456789012345678901234567890");

// 布尔类型
let bool1 = true;
let bool2 = false;
let bool3 = Boolean(1);       // true
let bool4 = Boolean(0);       // false
let bool5 = Boolean("hello"); // true
let bool6 = Boolean("");      // false
let bool7 = !!value;          // 双重否定转换

// Undefined类型
let undef1;
let undef2 = undefined;
let undef3 = void 0;          // 另一种写法

// Null类型
let null1 = null;

// Symbol类型(ES2015+)
let sym1 = Symbol("description");
let sym2 = Symbol("description");
console.log(sym1 === sym2);  // false,唯一性

// 全局Symbol注册表
let globalSym1 = Symbol.for("global");
let globalSym2 = Symbol.for("global");
console.log(globalSym1 === globalSym2);  // true

// Symbol作为对象属性键
let obj = {
    [Symbol("key")]: "value",
    [Symbol.iterator]: function*() {
        yield 1;
        yield 2;
    }
};

// 对象类型(Object Types)
// 普通对象
let obj1 = {key: "value"};
let obj2 = new Object();
let obj3 = Object.create(null);  // 无原型对象

// 数组
let arr1 = [1, 2, 3];
let arr2 = new Array(1, 2, 3);
let arr3 = Array.of(1, 2, 3);
let arr4 = Array.from("hello");  // ['h', 'e', 'l', 'l', 'o']

// 函数
function func1() {}
let func2 = function() {};
let func3 = () => {};
let func4 = new Function('a', 'b', 'return a + b');

// 日期对象
let date1 = new Date();
let date2 = new Date(2024, 0, 1);  // 2024年1月1日
let date3 = new Date("2024-01-01");

// 正则表达式
let regex1 = /pattern/;
let regex2 = new RegExp("pattern");
let regex3 = /pattern/gi;  // 全局、忽略大小写

// 错误对象
let error1 = new Error("错误信息");
let error2 = new TypeError("类型错误");
let error3 = new RangeError("范围错误");

// Map对象(ES2015+)
let map = new Map();
map.set("key", "value");
map.set(1, "number");
map.set(true, "boolean");

// Set对象(ES2015+)
let set = new Set();
set.add(1);
set.add(2);
set.add(2);  // 重复值不会添加
set.add("string");

// WeakMap对象(ES2015+)
let weakMap = new WeakMap();
let keyObj = {};
weakMap.set(keyObj, "value");

// WeakSet对象(ES2015+)
let weakSet = new WeakSet();
weakSet.add(keyObj);

// Promise对象(ES2015+)
let promise = new Promise((resolve, reject) => {
    resolve("成功");
});

// Proxy对象(ES2015+)
let target = {key: "value"};
let proxy = new Proxy(target, {
    get: function(obj, prop) {
        return prop in obj ? obj[prop] : "默认值";
    }
});

// Reflect对象(ES2015+)
let objReflect = {};
Reflect.set(objReflect, 'key', 'value');
console.log(Reflect.get(objReflect, 'key'));

// 类(ES2015+)
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    
    greet() {
        console.log(`Hello, ${this.name}`);
    }
}

// 静态方法和属性
class MyClass {
    static staticProp = "静态属性";
    
    static staticMethod() {
        return "静态方法";
    }
}

// 私有字段(ES2022+)
class PrivateClass {
    #privateField = "私有字段";
    
    getPrivate() {
        return this.#privateField;
    }
}

// 类型检查
let value = "hello";

console.log(typeof value);        // "string"
console.log(typeof 123);          // "number"
console.log(typeof true);         // "boolean"
console.log(typeof undefined);    // "undefined"
console.log(typeof null);         // "object" (历史遗留问题)
console.log(typeof {});           // "object"
console.log(typeof []);           // "object"
console.log(typeof function(){}); // "function"
console.log(typeof Symbol());     // "symbol"
console.log(typeof 123n);         // "bigint"

// instanceof 检查
console.log([] instanceof Array);        // true
console.log({} instanceof Object);       // true
console.log(function(){} instanceof Function); // true
console.log(new Date() instanceof Date); // true

// Array.isArray 检查
console.log(Array.isArray([]));  // true
console.log(Array.isArray({}));  // false

// Object.prototype.toString 检查
console.log(Object.prototype.toString.call([]));      // "[object Array]"
console.log(Object.prototype.toString.call({}));      // "[object Object]"
console.log(Object.prototype.toString.call(null));    // "[object Null]"
console.log(Object.prototype.toString.call(undefined)); // "[object Undefined]"

// 类型转换
// 字符串转换
let strNum = String(123);
let strBool = String(true);
let strObj = String({key: "value"});
let strNull = String(null);
let strUndef = String(undefined);

// 数字转换
let numStr = Number("123");
let numBool = Number(true);
let numObj = Number({valueOf: () => 42});
let numParseInt = parseInt("123");
let numParseFloat = parseFloat("3.14");

// 布尔转换
let boolStr = Boolean("hello");
let boolNum = Boolean(0);
let boolObj = Boolean({});
let boolArr = Boolean([]);

// 隐式类型转换
let result1 = "5" + 3;      // "53" (字符串拼接)
let result2 = "5" - 3;      // 2 (数字减法)
let result3 = "5" * 3;      // 15 (数字乘法)
let result4 = "5" / 2;      // 2.5 (数字除法)
let result5 = "5" % 2;      // 1 (数字取模)

// == 和 === 的区别
console.log(5 == "5");      // true (类型转换后比较)
console.log(5 === "5");     // false (类型和值都比较)
console.log(0 == false);    // true
console.log(0 === false);   // false
console.log(null == undefined);  // true
console.log(null === undefined); // false

// 类型转换规则
// ToPrimitive - 转换为原始值
let objToPrim = {
    valueOf: function() { return 42; },
    toString: function() { return "hello"; }
};
console.log(+objToPrim);  // 42 (优先调用valueOf)

// ToNumber - 转换为数字
console.log(Number("123"));    // 123
console.log(Number("3.14"));   // 3.14
console.log(Number(""));       // 0
console.log(Number("hello"));  // NaN
console.log(Number(true));     // 1
console.log(Number(false));    // 0
console.log(Number(null));     // 0
console.log(Number(undefined)); // NaN

// ToString - 转换为字符串
console.log(String(123));      // "123"
console.log(String(true));     // "true"
console.log(String(null));     // "null"
console.log(String(undefined)); // "undefined"
console.log(String({}));       // "[object Object]"

// ToBoolean - 转换为布尔值
// 以下值转换为false
console.log(Boolean(false));   // false
console.log(Boolean(0));       // false
console.log(Boolean(-0));      // false
console.log(Boolean(0n));      // false
console.log(Boolean(""));      // false
console.log(Boolean(null));    // false
console.log(Boolean(undefined)); // false
console.log(Boolean(NaN));     // false

// 其他所有值转换为true
console.log(Boolean("0"));     // true
console.log(Boolean("false")); // true
console.log(Boolean([]));      // true
console.log(Boolean({}));      // true
console.log(Boolean(function(){})); // true

// 类型安全函数
function safeAdd(a, b) {
    if (typeof a !== 'number' || typeof b !== 'number') {
        throw new TypeError('参数必须是数字');
    }
    return a + b;
}

// TypeScript类型注释(虽然不是原生支持)
/**
 * @param {number} a
 * @param {number} b
 * @returns {number}
 */
function add(a, b) {
    return a + b;
}

// JSDoc类型注释
/**
 * @typedef {Object} User
 * @property {string} name
 * @property {number} age
 * @property {string[]} hobbies
 */

/**
 * @param {User} user
 * @returns {string}
 */
function greetUser(user) {
    return `Hello, ${user.name}`;
}

// 类型守卫
function isString(value) {
    return typeof value === 'string';
}

function process(value) {
    if (isString(value)) {
        // TypeScript中这里value会被推断为string类型
        return value.toUpperCase();
    }
    return value;
}

以上是三种语言在变量和类型方面的详细对照,涵盖了基本语法、数据类型、类型转换、作用域等核心概念。每种语言都有其独特的特性和最佳实践。

❌
❌