学习笔记十五——rust柯里化,看不懂 `fn add(x) -> impl Fn(y)` 的同学点进来!

🧠 Rust 柯里化从零讲透:看不懂 fn add(x) -> impl Fn(y) 的同学点进来!

🍔 一、什么是柯里化?先用一个超好懂的生活比喻

假设你在点一个汉堡:

text 复制代码
你说:我要点一个鸡腿汉堡!
店员说:好的,请先选肉 → 鸡腿
再选酱料 → 辣酱
最后选芝士 → 加!

是不是你并没有一次性说完,而是一步一步选项配置完成?每次传一个参数。

这就是"柯里化"的思想:

把一个需要多个参数的函数,变成"一层一层传一个参数"的函数结构。


💡 二、我们来对比看:正常函数 VS 柯里化函数

rust 复制代码
// 普通函数(一次性传两个参数)
fn add(x: i32, y: i32) -> i32 {
    x + y
}

调用方式是:

rust 复制代码
let result = add(2, 3);  // 直接给两个参数,得到结果 5

柯里化版本写法是这样的:

rust 复制代码
fn add(x: i32) -> impl Fn(i32) -> i32 {
    move |y| x + y
}

🔍 三、这一句到底怎么读?我们逐字逐句拆解!

📘 原始代码:

rust 复制代码
fn add(x: i32) -> impl Fn(i32) -> i32 {
    move |y| x + y
}

🧩 第一步:函数签名部分解读

rust 复制代码
fn add(x: i32)

意思是:这个函数叫 add,它接收一个参数 x,类型是 i32


🧩 第二步:箭头 -> 后面部分

rust 复制代码
-> impl Fn(i32) -> i32

这部分表示:

函数的返回值是 一个"能接收 i32,并返回 i32"的函数

说人话就是:

你调用 add(10) 得到的,并不是一个数字,而是一个函数!

而这个函数就像这样:

rust 复制代码
|y| 10 + y

这个函数"等着你传第二个参数 y",然后它会用之前的 x = 10 加上 y,返回结果。


🧩 第三步:move |y| x + y 是什么意思?

这句其实是 Rust 的"闭包写法",也叫"匿名函数":

rust 复制代码
move |y| x + y

拆开解释:

部分 解释
move 让闭包把外部变量(比如 x)带进来,封装进去
` y
x + y 闭包的执行体逻辑:x 和 y 相加

所以这个闭包表示:

"我是一个能接受 y 的函数,我知道外部的 x,然后返回 x + y 的结果。"


🧪 举个完整例子,来看怎么使用这个柯里化函数:

rust 复制代码
fn add(x: i32) -> impl Fn(i32) -> i32 {
    move |y| x + y
}

fn main() {
    let add_10 = add(10);
    // ↑ 第一步,传入参数 x = 10,返回一个闭包
    //   这个闭包相当于 |y| 10 + y

    let result = add_10(5);
    // ↑ 第二步,再传入 y = 5
    //   执行的是:10 + 5 = 15

    println!("结果是: {}", result);  // 输出 结果是: 15
}

🧱 四、图解:柯里化是怎么"层层返回"的?

复制代码
fn add(x)
↓
返回一个函数 |y| {
    用到之前的 x + 当前的 y
}

你可以理解为:第一次函数调用"定制好了逻辑",但还没执行;第二次才执行。


💭 五、为什么我们明明没有看到 y 参数,却能传 y?

这是**"闭包"**的关键作用。

闭包 move |y| x + y 是个"函数",你可以存它、传它、执行它。

当你写:

rust 复制代码
let add_10 = add(10);

这个 add_10 是个函数,你可以像下面这样用它:

rust 复制代码
add_10(1)
add_10(2)
add_10(100)

每次传进去的就是参数 y

这个 y 就是在你真正执行闭包的时候才"出现"。


✅ 六、你现在可以这样理解这句代码:

rust 复制代码
fn add(x: i32) -> impl Fn(i32) -> i32 {
    move |y| x + y
}

🔹 它是一个"做加法的函数工厂":

你告诉它 x 它就给你返回一个"只差 y"的函数。

你什么时候需要加 y,再传进去,它才给你结果。


🧰 七、为什么要这么麻烦搞柯里化?

因为柯里化有这些强大优势:

应用场景 优势
🎯 提前绑定参数 可以预设 x,只改 y,比如 add_10 = add(10)
🧱 组合函数 可以把多个闭包组合成管道式处理函数
🧩 配置默认项 比如封装 IP,后续只改端口(见下文)
📦 构造工厂函数 像"做函数的函数",可复用、易测试

🔁 八、再看两个实用场景


🟢 配置化参数:绑定一部分值

rust 复制代码
fn connect(ip: &str) -> impl Fn(u16) -> String {
    let ip = ip.to_string(); // 复制字符串所有权进闭包
    move |port| format!("连接 {}:{}", ip, port)
}

用法:

rust 复制代码
let local = connect("127.0.0.1");
println!("{}", local(8080));  // 连接 127.0.0.1:8080
println!("{}", local(3000));  // 连接 127.0.0.1:3000

优势:IP 只写一次,port 可动态传。更灵活、结构清晰


🟢 函数组合:先加再乘

rust 复制代码
fn add(x: i32) -> impl Fn(i32) -> i32 {
    move |y| x + y
}
fn mul(x: i32) -> impl Fn(i32) -> i32 {
    move |y| x * y
}

fn main() {
    let step1 = add(2); // +2
    let step2 = mul(3); // *3

    let result = step2(step1(4)); // (4 + 2) * 3 = 18
    println!("组合结果: {}", result);
}

📘 九、总结:你现在该怎么读懂这一句代码?

rust 复制代码
fn add(x: i32) -> impl Fn(i32) -> i32 {
    move |y| x + y
}

✅ 翻译成人话:

"我这个函数 add,先让你告诉我 x,我会返回一个新的函数,这个新函数能接收 y,然后把 x + y 返回。"

它是个两步操作函数,每步只干一件事。


🧠 十、关键记忆方法

方法 说明
📦 想象闭包是"能记住变量的盒子" `move
🔁 柯里化就是函数拆分,每层一个参数 f(x, y) 变成 f(x)(y)
🧠 多举例,多写"函数返回函数"的结构 自己模仿写"加法器、乘法器、配置函数"等

如果你想,我也可以做一个动画演示图,帮助你形象化理解"add(10) 返回函数"的过程

相关推荐
知识分享小能手1 小时前
React学习教程,从入门到精通, React 属性(Props)语法知识点与案例详解(14)
前端·javascript·vue.js·学习·react.js·vue·react
汇能感知4 小时前
摄像头模块在运动相机中的特殊应用
经验分享·笔记·科技
阿巴Jun4 小时前
【数学】线性代数知识点总结
笔记·线性代数·矩阵
茯苓gao4 小时前
STM32G4 速度环开环,电流环闭环 IF模式建模
笔记·stm32·单片机·嵌入式硬件·学习
是誰萆微了承諾4 小时前
【golang学习笔记 gin 】1.2 redis 的使用
笔记·学习·golang
DKPT5 小时前
Java内存区域与内存溢出
java·开发语言·jvm·笔记·学习
aaaweiaaaaaa5 小时前
HTML和CSS学习
前端·css·学习·html
ST.J5 小时前
前端笔记2025
前端·javascript·css·vue.js·笔记
Suckerbin6 小时前
LAMPSecurity: CTF5靶场渗透
笔记·安全·web安全·网络安全
看海天一色听风起雨落6 小时前
Python学习之装饰器
开发语言·python·学习