Rust 与 C# 语法差异详细对比
作为从 C# 转向 Rust 的开发者,理解两者语法设计的核心差异有助于快速适应。以下从基础语法、核心特性到高级功能进行对比,并结合搜索结果中的技术特性分析:
一、基础语法对比
| 语法维度 | C# | Rust | 关键差异 |
|---|
| 变量声明 | int x = 5; 或 var x = 5; (类型推断) | let x = 5; (不可变) 或 let mut x = 5; (可变) | Rust 变量默认不可变,需显式用 mut 声明可变变量;C# 默认允许修改 5。 |
| 函数定义 | public int Add(int a, int b) { ... } | fn add(a: i32, b: i32) -> i32 { ... } | Rust 函数参数需显式标注类型,返回值用 -> 类型 声明;C# 支持隐式类型推断 5。 |
| 全局函数 | 仅允许在静态类中定义 (如 static class Utils { ... }) | 直接支持全局函数 (无需类包裹) | Rust 无需类/命名空间包裹顶层函数,C# 严格依赖类结构 5。 |
| 函数重载 | 支持 (通过参数类型/数量区分) | 不支持 (需通过不同函数名或泛型实现) | C# 支持函数重载,Rust 需显式命名不同函数(如 add_i32/add_f64)5。 |
| 入口函数 | static void Main(string[] args) { ... } | fn main() { ... } 或带参数 fn main(args: Vec<String>) { ... } | Rust 入口函数更简洁,参数通过 std::env::args 获取。 |
二、核心特性对比
1. 类型系统
| 特性 | C# | Rust | 说明 |
|---|
| 基本类型 | int/string/bool 等,值类型/引用类型分离 | i32/String/bool 等,无值类型/引用类型概念 | Rust 通过所有权系统管理内存,而非 C# 的值类型(栈)/引用类型(堆)二分法 1。 |
| 字符串类型 | string (引用类型,UTF-16 编码) | String (堆分配) / &str (字符串切片,UTF-8 编码) | Rust 区分动态字符串 String 和静态字符串切片 &str,C# 统一为 string。 |
| 泛型 | List<T> 等,支持泛型约束 | Vec<T> 等,泛型约束更严格 (如 T: Trait) | 两者均支持泛型,但 Rust 泛型需通过 trait 约束,C# 用 where 子句 5。 |
2. 内存管理与安全性
| 特性 | C# | Rust | 说明 |
|---|
| 内存管理 | 垃圾回收 (GC) 自动管理 | 编译期所有权系统 (无 GC) | C# 依赖 GC 回收内存,Rust 通过所有权/借用规则在编译期确保内存安全,无运行时开销 1。 |
| 空值处理 | 允许 null (引用类型默认可空) | 显式通过 Option<T> 枚举处理 (非空安全) | Rust 无 null,需用 Option::Some(value)/Option::None 表示可能为空的值,编译期避免空指针异常 1。 |
| 悬垂引用 | 可能出现 (如 var x = new object(); x = null; 后引用失效) | 编译期禁止 (通过借用规则确保引用有效) | Rust 的借用检查器(Borrow Checker)杜绝悬垂引用,C# 需手动避免空引用 1。 |
3. 控制流与模式匹配
| 特性 | C# | Rust | 说明 |
|---|
| 条件表达式 | if (condition) { ... } else { ... } | if condition { ... } else { ... } | 语法类似,但 Rust 允许 if 作为表达式返回值(如 let x = if a > b { 1 } else { 0 };)。 |
| 模式匹配 | switch 语句 (C# 8.0+ 支持模式匹配) | match 表达式 (功能更强大) | Rust match 支持枚举、结构体、范围等复杂模式,且强制覆盖所有可能分支(无 default 时)。 |
| 循环 | for/while/do-while | for/while/loop (无限循环) | Rust 无 do-while,可用 loop { ... if condition { break; } } 替代。 |
4. 错误处理
| C# 方式 | Rust 方式 | 核心差异 |
|---|
try-catch 异常捕获 | Result<T, E> 枚举 + ? 运算符 | C# 通过异常传递错误,Rust 通过返回 Result 类型显式处理,编译期强制检查未处理错误 1。 |
throw new Exception("错误") | Err(MyError::Message("错误".to_string())) | Rust 错误是值而非异常,需显式返回;C# 异常会中断执行流。 |
| 可忽略异常 (不推荐) | unwrap() (强制解包,出错时崩溃) 或 expect("提示") | Rust 鼓励显式处理错误,unwrap 仅用于原型开发。 |
三、高级功能对比
1. 面向对象与 trait 抽象
| C# 特性 | Rust 对应实现 | 说明 |
|---|
类继承 (class B : A { ... }) | 组合 + trait 实现 (struct B { a: A } + impl Trait for B { ... }) | Rust 无类继承,通过 trait 定义接口,结构体通过 impl Trait 添加行为 1。 |
接口 (interface IMyInterface { ... }) | trait (trait MyTrait { ... }) | Rust trait 可包含默认方法实现,C# 接口需显式实现。 |
虚方法 (virtual/override) | trait 方法覆盖 | Rust 通过 impl Trait for Type 重写 trait 方法,无运行时多态开销。 |
2. 泛型与模板
| C# 泛型 | Rust 泛型式样 | [5]() | |--------------------------------------|---------------------------------------|---------| | List<T> Where T : IComparable { ... } | struct MyList<T: Ord> { ... } | Rust 泛型约束通过 : 直接标注在类型旁,更简洁。 | | 运行时泛型类型信息 (RTTI) | 编译期单态化 (无运行时类型信息默认) | Rust 泛型通过单态化生成具体类型代码,C# 依赖运行时类型信息。 |
四、语法风格与代码组织
| 维度 | C# | Rust |
|---|
| 代码文件结构 | 按命名空间和类组织,需显式 using 导入 | 按模块 (mod) 组织,通过 use 导入路径,支持嵌套模块。 |
| 注释 | // 单行 /* 多行 */ /// XML 文档注释 | // 单行 /* 多行 */ /// 文档注释 (生成 rustdoc) |
| 分号规则 | 语句必须以分号结尾 | 表达式末尾分号可选(无分号则作为返回值) |
总结:核心差异一览
- 内存安全:Rust 通过所有权/借用系统在编译期确保安全,C# 依赖 GC 运行时管理 1。
- 类型系统:Rust 更严格(显式类型标注、无
null),C# 更灵活(隐式推断、类继承)5。 - 代码组织:Rust 无类约束,支持全局函数和模块;C# 严格依赖类和命名空间 5。
- 错误处理:Rust 显式
Result 类型,C# 隐式异常机制 1。
建议从 变量声明、函数定义、错误处理 三个基础点开始实践,逐步过渡到所有权和 trait 系统,可显著降低学习曲线。