成为Unity客户端开发已经快3年了,意味着用了3年的C#,不过学生时代几乎啥语言都接触过,最近打算深入研究游戏引擎,使用Godot游戏引擎进行开发,它使用的是C++,但却发现,C++不像C#那样我只需要在乎逻辑怎么写,C++需要我考虑代码如何构建,使用类似CMake、Scons这种构建工具,因此我打算从头了解一遍编程语言,深入了解为什么会有这种差异。
编程语言分类
编程语言的分类方式多样,不同维度可以交叉组合。以下是主要分类方式及典型示例:
一、按执行方式分类
| 类别 | 特点 | 典型语言 |
|---|---|---|
| 编译型 | 源代码 → 机器码(直接执行) | C、C++、Rust、Go |
| 解释型 | 源代码 → 逐行解释执行 | Python、Ruby、JavaScript(传统) |
| 混合型 | 编译+解释(如JIT/AOT) | Java(JVM JIT)、JavaScript(V8引擎) |
二、按编程范式分类
| 范式 | 核心思想 | 典型语言 |
|---|---|---|
| 面向对象 | 以对象为核心(封装、继承、多态) | Java、C++、Python |
| 函数式 | 以函数为核心(不可变数据、高阶函数) | Haskell、Scala、Erlang |
| 过程式 | 以过程/函数调用顺序为核心 | C、Pascal |
| 逻辑式 | 基于形式逻辑推理 | Prolog |
| 脚本式 | 轻量级、快速开发 | Python、Perl、Bash |
三、按抽象级别分类
| 级别 | 特点 | 典型语言 |
|---|---|---|
| 低级语言 | 接近硬件,需手动管理资源 | Assembly、C |
| 高级语言 | 抽象程度高,屏蔽硬件细节 | Python、Java、C# |
四、按用途分类
| 领域 | 特点 | 典型语言 |
|---|---|---|
| 通用编程 | 适用于多种场景 | Python、Java、C++ |
| 系统编程 | 操作系统、驱动开发 | C、Rust、Zig |
| Web开发 | 前端/后端开发 | JavaScript、PHP、Ruby |
| 数据科学 | 数据分析、机器学习 | Python、R、Julia |
| 嵌入式 | 资源受限设备 | C、Lua、MicroPython |
五、按类型系统分类
| 类型系统 | 特点 | 典型语言 |
|---|---|---|
| 静态类型 | 变量类型在编译时确定 | C++、Java、Rust |
| 动态类型 | 变量类型在运行时确定 | Python、JavaScript、Ruby |
| 强类型 | 禁止隐式类型转换 | Python、Haskell |
| 弱类型 | 允许隐式类型转换(如强制转换) | JavaScript、PHP |
六、按并发模型分类
| 模型 | 特点 | 典型语言 |
|---|---|---|
| 线程模型 | 基于操作系统线程 | Java、C++(std::thread) |
| Actor模型 | 通过消息传递实现并发 | Erlang、Akka(Scala) |
| 协程模型 | 轻量级用户态线程 | Go(goroutine)、Python(asyncio) |
七、按运行环境分类
| 环境 | 特点 | 典型语言 |
|---|---|---|
| 独立运行 | 直接生成可执行文件 | C、Go |
| 虚拟机依赖 | 需虚拟机/运行时环境 | Java(JVM)、C#(CLR) |
| 浏览器环境 | 运行在浏览器中 | JavaScript、TypeScript |
八、按设计哲学分类
| 哲学 | 特点 | 典型语言 |
|---|---|---|
| 简洁性 | 语法极简(如强制缩进) | Python、Go |
| 多范式支持 | 支持多种编程范式 | Scala、F# |
| 安全优先 | 内存安全、无指针 | Rust、Go |
总结:分类不是互斥的
- 示例:
- Python:高级、解释型、动态类型、多范式(面向对象+函数式)。
- Rust:系统级、静态类型、编译型、内存安全。
- JavaScript:脚本式、动态类型、浏览器环境、多范式(事件驱动+函数式)。
实际选择语言时需综合考虑:
- 项目需求(性能、开发效率)
- 团队熟悉度
- 生态支持(库、工具链)
执行方式分类
编程语言按执行方式分类,主要分为编译型、解释型和混合型(如JIT)。这种分类源于计算机底层执行机制的差异,以及开发者对性能、开发效率和跨平台能力的权衡。以下是详细分类及其背后的逻辑:
一、编译型语言(Compiled Languages)
graph LR
A[源代码: .cpp] --> B(预处理)
B --> C(编译)
C --> D(汇编)
D --> E(链接)
E --> F[可执行文件]
执行流程
- 编译:源代码通过编译器(如GCC、Clang)一次性转换为机器码(可执行文件)。
- 执行:直接由操作系统运行生成的二进制文件。
典型语言
C、C++、Rust、Go、Swift。
为何这样设计?
- 性能优先:
- 机器码直接由CPU执行,无需运行时解释,速度最快。
- 适合系统级开发(如操作系统、游戏引擎)。
- 硬件控制:
- 编译器可优化内存管理(如手动内存分配)、寄存器分配等底层细节。
- 静态类型系统:
- 编译时检查类型错误(如C++的强类型),减少运行时崩溃风险。
代价
- 跨平台性差:需为不同平台(Windows/Linux)编译不同二进制文件。
- 开发效率低:编译时间长,修改代码后需重新编译。
二、解释型语言(Interpreted Languages)
graph LR
A[源代码: .py] --> B(解释器逐行解析)
B --> C[生成字节码: .pyc]
C --> D[执行字节码]
执行流程
- 逐行解析:解释器(如Python解释器)逐行读取源代码。
- 即时翻译:将每行代码转换为中间表示(如字节码)或直接执行。
典型语言
Python、Ruby、JavaScript(传统浏览器环境)、Bash。
为何这样设计?
- 开发效率高:
- 无需编译步骤,修改代码后立即执行,适合快速迭代(如脚本任务)。
- 跨平台性强:
- 只需分发源代码,解释器负责适配不同平台(如Python的“一次编写,到处运行”)。
- 动态特性支持:
- 支持动态类型(运行时确定变量类型)、反射等灵活功能。
代价
- 性能较低:逐行解释执行,无法充分利用硬件优化。
- 启动时间长:大型脚本(如Python数据分析)可能因解释器初始化而变慢。
三、混合型语言(Hybrid Execution)
graph LR
A[源代码: .java] --> B(编译)
B --> C[生成字节码: .class]
C --> D{运行时环境}
D -->|首次执行| E[JIT编译为机器码]
D -->|热点代码| F[直接执行机器码]
E --> G[可执行程序]
F --> G
核心模式
结合编译与解释的优势,常见两种实现:
- 即时编译(JIT, Just-In-Time):
- 源代码先编译为中间字节码(如Java的
.class),运行时由虚拟机(JVM)动态编译为机器码。 - 典型语言:Java、C#、JavaScript(V8引擎)。
- 源代码先编译为中间字节码(如Java的
- AOT编译(Ahead-Of-Time):
- 在运行前将源代码或中间代码编译为机器码,但不同于传统编译型语言(如Rust的LLVM优化)。
- 典型语言:Swift、Rust。
为何这样设计?
- 平衡性能与跨平台:
- JIT在运行时优化热点代码(如Java的HotSpot JVM),接近编译型性能。
- 字节码保持跨平台能力(如Java的“一次编译,到处运行”)。
- 动态优化:
- JIT可根据实际运行数据优化代码(如V8引擎对JS的优化)。
代价
- 内存占用高:需同时维护字节码和JIT编译后的机器码。
- 启动延迟:JIT初始化阶段可能影响性能(如Java应用冷启动较慢)。
四、分类的核心逻辑:性能 vs 灵活性
| 分类 | 核心目标 | 适用场景 | 代表技术 |
|---|---|---|---|
| 编译型 | 最大化执行效率 | 操作系统、高频交易、游戏引擎 | C/C++、Rust |
| 解释型 | 开发效率与跨平台性 | 脚本任务、Web后端、数据分析 | Python、JavaScript |
| 混合型 | 性能与灵活性的折中 | 企业级应用、跨平台移动开发 | Java(JVM)、JavaScript(V8) |
五、为什么会出现这些差异?
1. 硬件与操作系统的限制
- 编译型语言直接操作硬件资源(如内存地址),但不同平台的指令集(x86/ARM)不同,导致代码无法通用。
- 解释型语言通过虚拟机(如JVM)抽象硬件差异,实现跨平台。
2. 开发者的效率需求
- 编译型语言需要手动管理内存和底层细节,适合有经验的开发者;
- 解释型语言提供高级抽象(如自动垃圾回收),降低学习门槛。
3. 语言特性的复杂度
- 动态类型、反射等特性难以在编译时完全优化,更适合解释执行(如Python的灵活性)。
- 静态类型语言(如Rust)可通过编译时检查提前发现问题,提升安全性。
六、现代趋势:打破传统边界
- 编译型语言引入解释特性:
- Go语言通过
go run直接解释执行代码,兼顾开发效率。
- Go语言通过
- 解释型语言引入JIT:
- JavaScript的V8引擎将代码编译为机器码,性能接近C++。
- 全栈语言的混合模式:
- TypeScript(编译为JS) + WebAssembly(AOT编译)结合两者的优势。
总结
编程语言的执行方式分类,本质是工程需求与硬件能力的博弈结果:
- 编译型:追求极致性能,牺牲灵活性。
- 解释型:强调开发效率和跨平台,牺牲速度。
- 混合型:在两者间寻找平衡,适应复杂场景。
选择建议:
- 开发系统级软件(如操作系统)→ C/C++
- 快速构建Web应用 → JavaScript/Python
- 需要跨平台且高性能 → Java(JVM) 或 Rust
编程范式分类
编程语言按编程范式分类,常见的核心范式有以下四种。每种范式代表一种独特的代码组织逻辑和问题解决思路:
1. 面向对象编程(OOP)
核心思想:
- 将现实世界抽象为对象(包含数据和行为),通过封装隐藏细节、继承复用代码、多态实现灵活调用。
典型语言:Java、C++、Python、C#
适用场景: - 大型系统(如GUI应用、游戏开发)
- 需要模块化扩展的项目
代码示例:
| |
2. 函数式编程(FP)
核心思想:
- 以函数为基本单元,强调纯函数(输入相同则输出相同)、不可变数据,避免副作用。
典型语言:Haskell、Scala、JavaScript(部分支持)
适用场景: - 并发编程(无共享状态)
- 数据处理(如Map/Reduce)
代码示例:
| |
3. 过程式编程
核心思想:
- 按步骤顺序执行函数,通过函数调用组织逻辑,数据与操作分离。
典型语言:C、Pascal
适用场景: - 系统级开发(如操作系统内核)
- 小型脚本工具
代码示例:
| |
4. 事件驱动编程
核心思想:
- 由事件(如点击、网络请求)触发响应,通过回调函数或事件循环处理异步操作。
典型语言:JavaScript、Python(asyncio)
适用场景: - GUI应用、实时系统
- 高并发服务(如Web服务器)
代码示例:
| |
范式对比总结
| 范式 | 核心单元 | 典型场景 | 关键优势 |
|---|---|---|---|
| 面向对象 | 对象 | 大型系统、模块化扩展 | 代码复用(继承)、灵活性(多态) |
| 函数式 | 函数 | 并发编程、数据处理 | 无副作用、易于测试 |
| 过程式 | 函数 | 系统开发、小型工具 | 简单直接、执行高效 |
| 事件驱动 | 事件 | GUI应用、实时服务 | 高响应性、资源利用率高 |
重要提示
多范式融合:现代语言(如Python、JavaScript)通常支持多种范式。
1 2 3 4 5# Python示例:混合OOP和函数式 numbers = [1, 2, 3] squared = list(map(lambda x: x**2, numbers)) # 函数式 class Calculator: # 面向对象 def square(self, x): return x**2选择建议:
- 开发商业系统 → 面向对象(Java/C#)
- 高并发后端 → 函数式(Scala/Elixir)
- 硬件操作 → 过程式(C/Rust)
- 前端交互 → 事件驱动(JavaScript)
抽象级别分类
编程语言按抽象级别分类,核心依据是语言离硬件底层远近、对开发者的屏蔽程度和代码控制精细度。以下是三级分类详解:
一、低级语言(Low-Level Languages)
抽象特点:
- 直接映射硬件指令(如寄存器、内存地址)
- 开发者需手动管理底层资源(内存分配、CPU指令)
典型语言: - 汇编语言(Assembly):
- 直接对应机器码(如
MOV AX, 5→ 移动数字5到AX寄存器)。 - 应用场景:操作系统内核开发、嵌入式设备驱动。
- 直接对应机器码(如
- 机器语言(二进制代码):
- 由0和1组成,CPU直接执行(如
10110000 00000101→ 将5存入寄存器)。
- 由0和1组成,CPU直接执行(如
代码示例(x86汇编):
| |
二、中级语言(Mid-Level Languages)
抽象特点:
- 平衡控制与抽象:提供基础数据结构(数组、结构体)和流程控制(循环、条件),但仍暴露指针等底层操作。
- 开发者需管理内存但可忽略指令集细节。
典型语言: - C语言:
- 直接操作内存指针(如
int *ptr = &a;)。 - 应用场景:操作系统、硬件驱动、高性能计算(如Linux内核用C编写)。
- 直接操作内存指针(如
- C++(部分特性):
- 支持面向对象(类、继承),但保留指针操作(如
int* p = new int(10);)。
- 支持面向对象(类、继承),但保留指针操作(如
代码示例(C语言指针操作):
| |
三、高级语言(High-Level Languages)
抽象特点:
- 完全屏蔽硬件细节:自动内存管理(垃圾回收)、丰富的数据结构(字典、对象)。
- 语法接近自然语言(如英语单词),开发效率高。
典型语言: - Python:
- 自动内存回收,无需声明变量类型(如
name = "Alice")。
- 自动内存回收,无需声明变量类型(如
- Java:
- 虚拟机(JVM)屏蔽平台差异,自带垃圾回收。
- JavaScript:
- 解释执行,浏览器/Node.js环境抽象底层操作。
代码示例(Python高级抽象):
| |
抽象级别对比总结
| 级别 | 硬件依赖 | 内存管理 | 开发效率 | 性能 | 典型场景 |
|---|---|---|---|---|---|
| 低级语言 | 直接依赖 | 手动 | 极低 | 最高 | 操作系统内核、驱动 |
| 中级语言 | 间接依赖 | 手动/半自动 | 中等 | 高 | 系统软件、游戏引擎 |
| 高级语言 | 完全屏蔽 | 自动 | 高 | 中/低 | Web应用、数据分析、AI |
关键说明
为什么C/C++属于中级?
- C/C++允许直接操作内存(如指针),但又提供高级抽象(C++的类、模板),介于低级和高级之间。
现代语言的混合抽象:
- Rust:高级语法(模式匹配、错误处理) + 低级控制(无垃圾回收,零成本抽象)。
- Go:高级并发模型(goroutine) + 中级内存管理(手动释放资源)。
抽象级别的核心价值:
- 低级语言:极致性能 → 适合航空航天、高频交易。
- 高级语言:快速开发 → 适合互联网应用、脚本工具。
选择建议:
- 开发硬件驱动 → C/汇编
- 构建大型游戏引擎 → C++
- 快速开发Web应用 → Python/JavaScript