Rust 函数完整知识点详解

Rust 函数完整知识点详解

涵盖 :基础语法、参数分类、生命周期、泛型、async、unsafe 等

重点:所有权与借用规则、返回值内存规律、高频易错点


目录

  1. 基础语法结构
  2. 参数分类
  3. 函数作用域与位置
  4. 函数所有权、借用生命周期
  5. 函数类型、函数指针
  6. 四类可调用对象
  7. 参数模式解构
  8. 泛型函数
  9. async 异步函数(#九 async-异步函数)
  10. unsafe 函数(#十 unsafe-函数)
  11. 函数返回值与栈/堆内存规律
  12. 高频易错点
  13. 速记口诀

一、基础语法结构

rust 复制代码
// 标准格式:fn 函数名 (参数:类型) -> 返回值类型 { 函数体 }
fn add(a: i32, b: i32) -> i32 {
    a + b // 表达式,无分号 = 返回值
}

// 调用
let res = add(1, 2);

核心规则

  1. 关键字 fn 定义函数
  2. 参数必须标注类型,不能省略
  3. 返回值用 -> 类型 声明
  4. 函数最后一行无分号 为返回表达式;加 ; 代表语句,返回 () 空元组

两种返回写法

rust 复制代码
// 1. 隐式返回(推荐,无分号)
fn one() -> i32 { 1 }

// 2. 显式 return(提前终止函数)
fn max(a: i32, b: i32) -> i32 {
    if a > b {
        return a;
    }
    b
}

// 无返回值:省略 ->,等价返回 ()
fn print_log(s: &str) {
    println!("{}", s);
}

二、参数分类

1. 普通值参数(所有权转移)

传入 StringVec 等堆类型会转移所有权,外部变量失效:

rust 复制代码
fn take_own(s: String) {
    println!("{}", s);
}
let s = "hi".to_string();
take_own(s);
// s 失效,不能再使用

2. 引用参数(借用,不转移所有权)

  • &T:不可变借用,只读
  • &mut T:可变借用,可修改内部数据
rust 复制代码
fn read(s: &String) {}
fn modify(s: &mut String) {
    s.push_str(" add");
}

let mut s = String::new();
modify(&mut s);
read(&s);

提示 :函数参数优先使用 &str 而非 &String,兼容字面量、String 引用,通用性更强。

3. 可变参数不存在,但有替代方案

Rust 没有 fn foo(...) 可变参数:

  • 固定多参数:直接罗列
  • 不定数量:传入切片 &[T]
  • format!/println! 语法糖是宏实现,不是函数可变参数

4. 元组多返回值

函数只能返回单个值,多数据用元组包装:

rust 复制代码
fn split_num(x: i32) -> (i32, i32) {
    (x / 10, x % 10)
}
let (high, low) = split_num(25);

三、函数作用域与位置

类型 说明 调用方式
顶层函数 直接写在 crate 根、模块内,全局可导入调用 func()
关联函数 写在 impl 类型 {} 内部,无 &self,常做构造器 new() Type::func()
实例方法 impl 内带 self / &self / &mut self instance.func()
内部函数 函数内部可定义子函数,仅内部可见 inner()
闭包 匿名函数,捕获上下文 closure()

关联函数示例

rust 复制代码
struct User;
impl User {
    // 关联函数
    fn new() -> Self { User }
}
let u = User::new();

内部函数示例

rust 复制代码
fn outer() {
    fn inner() {}
    inner();
}

四、函数所有权、借用生命周期

1. 生命周期标注(函数引用返回)

若返回引用来自入参,必须标注生命周期,约束借用关系:

rust 复制代码
// 'a 约束:返回切片生命周期等于输入切片
fn longest<'a>(a: &'a str, b: &'a str) -> &'a str {
    if a.len() > b.len() { a } else { b }
}
三条生命周期省略规则(大部分场景不用手动标)
  1. 函数只有一个引用参数,返回引用自动复用该生命周期
  2. 方法 &self,返回引用生命周期绑定 self
  3. 多个入参、返回其中某一个,必须手动标注

2. 不能返回局部变量的引用

局部变量栈分配,函数结束销毁,返回引用会悬垂引用,编译报错:

rust 复制代码
fn bad() -> &String {
    let s = String::new();
    &s // 报错
}

解决方案 :直接返回所有权 String,把数据移到调用方栈/堆。


五、函数类型、函数指针

1. 函数类型签名

rust 复制代码
// 接收两个 i32 返回 i32 的函数类型:fn(i32, i32) -> i32
let f: fn(i32, i32) -> i32 = add;
println!("{}", f(1, 3));

2. 函数指针作为参数(回调)

rust 复制代码
fn calc(a: i32, b: i32, op: fn(i32, i32) -> i32) -> i32 {
    op(a, b)
}
calc(2, 4, add);

函数指针 vs 闭包

类型 特点
fn 函数指针 无捕获环境,轻量
闭包 可捕获外部变量,分三种 Fn/FnMut/FnOnce

六、四类可调用对象(区分函数/方法/关联函数/闭包)

  1. 普通自由函数 fn :无依附类型,直接调用 add()
  2. 关联函数 :依附结构体/枚举,无 self,User::new()
  3. 实例方法 :带 self,实例调用 user.get_name()
  4. 闭包:匿名内联函数,捕获上下文
rust 复制代码
let add = |a, b| a + b;
add(1, 2);

七、参数模式解构

函数参数可直接解构元组、结构体,简化代码:

rust 复制代码
// 解构元组参数
fn print_point((x, y): (i32, i32)) {
    println!("{} {}", x, y);
}

struct User { name: String }

// 解构结构体
fn greet(User { name, .. }: User) {
    println!("{}", name);
}

八、泛型函数

函数支持泛型,实现通用逻辑,配合 trait 约束限制类型:

rust 复制代码
// 无约束泛型
fn echo<T>(v: T) -> T { v }

// trait 约束:只接收实现 Debug 的类型
use std::fmt::Debug;
fn print_debug<T: Debug>(val: T) {
    println!("{:?}", val);
}

// where 语法,多约束更清晰
fn max_val<T>(a: T, b: T) -> T
where
    T: PartialOrd,
{
    if a > b { a } else { b }
}

九、async 异步函数

async fn 返回 Future,不直接执行,需要执行器 .await 调度:

rust 复制代码
async fn fetch_data() -> String {
    "data".to_string()
}

// 调用必须在 async 上下文 await
async fn run() {
    let res = fetch_data().await;
}

十、unsafe 函数

标记 unsafe fn:调用者必须包裹 unsafe {},函数内部包含未定义行为风险操作(裸指针、FFI 等)

rust 复制代码
unsafe fn raw_ptr(p: *const u8) -> u8 {
    *p
}

// 调用必须 unsafe 块
unsafe {
    let x = 10;
    raw_ptr(&x as *const u8);
}

十一、函数返回值与栈/堆内存规律

返回类型 内存行为
基础类型 (i32/f64/元组/定长数组) 值拷贝到调用方栈
String/Vec/Box 堆类型 所有权移动,堆内存转移,无拷贝
引用 &T 仅胖指针/地址拷贝,数据本体不移动
局部栈变量引用 ❌ 绝对不能返回(悬垂引用)

十二、高频易错点

⚠️ 以下易错点需特别注意

  1. 参数不写类型直接报错,Rust 不支持类型推导函数参数
  2. 函数末尾加分号会返回 (),和声明的返回值类型不匹配则编译失败
  3. String 会转移所有权 ,后续无法使用;想保留用 &String/&str
  4. 返回局部变量引用必报错,要么返回所有权,要么提前外部传入
  5. 多入参、返回引用时,必须手动标注生命周期
  6. fn 函数指针无法捕获外部变量,捕获场景只能用闭包
  7. varargs 可变参数 ,不定参数统一用切片 &[T]

十三、速记口诀

rust 复制代码
fn 开头定义函数,参数类型不能省;
尾行无分号返回,return 可提前退出;
传值转移所有权,引用借用不转移;
返回引用标生命周期,局部引用不能返;
泛型配合 trait 约束,async 返回 Future;
关联函数::调用,实例方法点调用。
相关推荐
爱勇宝2 小时前
淡泊名利之前,先承认我们都很焦虑
前端·后端·程序员
菜鸟谢2 小时前
Rust 闭包(Closure)完整详解
后端
ServBay2 小时前
如何利用本地技术栈构建 0 成本 AI SaaS 雏形
后端·aigc·ai编程
菜鸟谢2 小时前
Rust 集合 + 迭代器完整详解
后端
杨利杰YJlio2 小时前
Codex桌面客户端上手:项目、插件与自动化实战
前端·后端
常铭2 小时前
【Java基础】01-HashMap的底层原理
后端·面试
幼儿园技术家2 小时前
实现 GEO 监控:从多引擎探测到优化闭环
前端·后端
掘金者阿豪2 小时前
微信小程序虚拟支付与广告转化回传实战记录
后端
ping某3 小时前
专栏-null 和 undefined 到底是什么?
前端·javascript·后端