函数与方法
你将学到: Rust 与 C# 中的函数与方法对比,表达式(expressions)与语句(statements)之间的关键区别,
if/match/loop/while/for语法,以及 Rust 的面向表达式设计如何消除了对三元运算符的需求。难度: 🟢 初级
C# 函数声明
// C# - 类中的方法
public class Calculator
{
// 实例方法
public int Add(int a, int b)
{
return a + b;
}
// 静态方法
public static int Multiply(int a, int b)
{
return a * b;
}
// 带有 ref 参数的方法
public void Increment(ref int value)
{
value++;
}
}
Rust 函数声明
// Rust - 独立函数
fn add(a: i32, b: i32) -> i32 {
a + b // 最后一行表达式无需 'return' 关键字
}
fn multiply(a: i32, b: i32) -> i32 {
return a * b; // 显式使用 return 也是可以的
}
// 带有可变引用的函数
fn increment(value: &mut i32) {
*value += 1;
}
fn main() {
let result = add(5, 3);
println!("5 + 3 = {}", result);
let mut x = 10;
increment(&mut x);
println!("递增后: {}", x);
}
表达式 vs 语句 (极其重要!)
graph LR
subgraph "C# — 语句 (Statements)"
CS1["if (cond)"] --> CS2["return 42;"]
CS1 --> CS3["return 0;"]
CS2 --> CS4["值通过 return 退出"]
CS3 --> CS4
end
subgraph "Rust — 表达式 (Expressions)"
RS1["if cond"] --> RS2["42 (无分号)"]
RS1 --> RS3["0 (无分号)"]
RS2 --> RS4["代码块本身就是值"]
RS3 --> RS4
end
style CS4 fill:#bbdefb,color:#000
style RS4 fill:#c8e6c9,color:#000
// C# - 语句 vs 表达式
public int GetValue()
{
if (condition)
{
return 42; // 这是一个语句
}
return 0; // 这是一个语句
}
#![allow(unused)]
fn main() {
// Rust - 一切皆可为表达式
fn get_value(condition: bool) -> i32 {
if condition {
42 // 表达式 (无分号)
} else {
0 // 表达式 (无分号)
}
// if-else 代码块本身就是一个返回值的表达式
}
// 甚至可以更简单 (类似于三元运算)
fn get_value_ternary(condition: bool) -> i32 {
if condition { 42 } else { 0 }
}
}
函数参数与返回类型
// 无参数,无返回值 (返回单元类型 ())
fn say_hello() {
println!("Hello!");
}
// 多个参数
fn greet(name: &str, age: u32) {
println!("{} is {} years old", name, age);
}
// 使用元组 (tuple) 返回多个值
fn divide_and_remainder(dividend: i32, divisor: i32) -> (i32, i32) {
(dividend / divisor, dividend % divisor)
}
fn main() {
let (quotient, remainder) = divide_and_remainder(10, 3);
println!("10 ÷ 3 = {} 余数为 {}", quotient, remainder);
}
控制流基础
条件语句
// C# if 语句
int x = 5;
if (x > 10)
{
Console.WriteLine("大数");
}
else if (x > 5)
{
Console.WriteLine("中数");
}
else
{
Console.WriteLine("小数");
}
// C# 三元运算符
string message = x > 10 ? "Big" : "Small";
#![allow(unused)]
fn main() {
// Rust if 表达式
let x = 5;
if x > 10 {
println!("大数");
} else if x > 5 {
println!("中数");
} else {
println!("小数");
}
// Rust 中将 if 作为表达式使用 (等效于三元运算)
let message = if x > 10 { "Big" } else { "Small" };
// 多个条件的表达式用法
let message = if x > 10 {
"Big"
} else if x > 5 {
"Medium"
} else {
"Small"
};
}
循环 (Loops)
// C# 循环
// For 循环
for (int i = 0; i < 5; i++)
{
Console.WriteLine(i);
}
// Foreach 循环
var numbers = new[] { 1, 2, 3, 4, 5 };
foreach (var num in numbers)
{
Console.WriteLine(num);
}
// While 循环
int count = 0;
while (count < 3)
{
Console.WriteLine(count);
count++;
}
#![allow(unused)]
fn main() {
// Rust 循环
// 基于范围的 for 循环
for i in 0..5 { // 0 到 4 (不包含末尾值)
println!("{}", i);
}
// 遍历集合
let numbers = vec![1, 2, 3, 4, 5];
for num in numbers { // 获取所有权 (Takes ownership)
println!("{}", num);
}
// 遍历引用 (更常用的方式)
let numbers = vec![1, 2, 3, 4, 5];
for num in &numbers { // 借用元素
println!("{}", num);
}
// While 循环
let mut count = 0;
while count < 3 {
println!("{}", count);
count += 1;
}
// 带 break 的无限循环
let mut counter = 0;
loop {
if counter >= 3 {
break;
}
println!("{}", counter);
counter += 1;
}
}
循环控制
// C# 循环控制
for (int i = 0; i < 10; i++)
{
if (i == 3) continue;
if (i == 7) break;
Console.WriteLine(i);
}
#![allow(unused)]
fn main() {
// Rust 循环控制
for i in 0..10 {
if i == 3 { continue; }
if i == 7 { break; }
println!("{}", i);
}
// 循环标签 (用于嵌套循环)
'outer: for i in 0..3 {
'inner: for j in 0..3 {
if i == 1 && j == 1 {
break 'outer; // 跳出外层循环
}
println!("i: {}, j: {}", i, j);
}
}
}
🏋️ 练习:温度转换器 (点击展开)
挑战:将下面的 C# 程序转换为地道的 Rust 代码。使用表达式、模式匹配和正确的错误处理。
// C# — 请将其转换为 Rust
public static double Convert(double value, string from, string to)
{
double celsius = from switch
{
"F" => (value - 32.0) * 5.0 / 9.0,
"K" => value - 273.15,
"C" => value,
_ => throw new ArgumentException($"Unknown unit: {from}")
};
return to switch
{
"F" => celsius * 9.0 / 5.0 + 32.0,
"K" => celsius + 273.15,
"C" => celsius,
_ => throw new ArgumentException($"Unknown unit: {to}")
};
}
🔑 参考答案
#[derive(Debug, Clone, Copy)]
enum TempUnit { Celsius, Fahrenheit, Kelvin }
fn parse_unit(s: &str) -> Result<TempUnit, String> {
match s {
"C" => Ok(TempUnit::Celsius),
"F" => Ok(TempUnit::Fahrenheit),
"K" => Ok(TempUnit::Kelvin),
_ => Err(format!("未知单位: {s}")),
}
}
fn convert(value: f64, from: TempUnit, to: TempUnit) -> f64 {
let celsius = match from {
TempUnit::Fahrenheit => (value - 32.0) * 5.0 / 9.0,
TempUnit::Kelvin => value - 273.15,
TempUnit::Celsius => value,
};
match to {
TempUnit::Fahrenheit => celsius * 9.0 / 5.0 + 32.0,
TempUnit::Kelvin => celsius + 273.15,
TempUnit::Celsius => celsius,
}
}
fn main() -> Result<(), String> {
let from = parse_unit("F")?;
let to = parse_unit("C")?;
println!("212°F = {:.1}°C", convert(212.0, from, to));
Ok(())
}
关键总结:
- 枚举 (Enums) 替代了幻数/魔法字符串 —— 穷尽匹配在编译阶段就能捕获缺失的单位。
Result<T, E>替代了异常机制 —— 调用者可以在函数签名中看到所有潜在的失败情况。match是一个返回值的表达式 —— 无需显式的return语句。