React Compiler 用 Rust 重写了,编译提速 10 倍——手写 useMemo 的日子到头了

几周前,微软把 TypeScript 编译器用 Go 重写,速度暴增 10 倍。

几周后,Meta 把 React Compiler 用 Rust 重写,核心转换逻辑同样快了 10 倍。

两件事隔着大洋接力发生,指向同一个结论:前端工具链的核心引擎,正在全面逃离 JavaScript。

那么 React Compiler 的 Rust 重写到底做了什么、怎么用、有什么影响。

一、事件还原:PR #36173 合并主仓

2026 年 6 月 18 日,GitHub 上 facebook/react 仓库合并了一个编号为 #36173 的 Pull Request------React Compiler 的完整 Rust 移植版正式进入主干。

主导这次移植的是 Meta 的 React 核心团队成员 Joseph Savona。整个 PR 包含 330 个 commits,新增超过 123,000 行 Rust 代码。

在 PR 描述的最后一段,他写了一句话:

"开发者花了大量时间设定架构、测试策略、增量迁移方案,反复打磨代码质量......但大部分代码是 AI 生成的。"

这句话在前端圈讨论了一周。架构是人设计的,代码是 AI 写的,1725 个测试用例一个不少地卡着质量线。这个模式后面再聊。

关键时间线

时间 事件
2024 React Compiler(原名 React Forget)首次公开,TS 实现
2025 末 React Compiler v1.0 稳定发布,已用于 Instagram 生产环境
2026-06-18 PR #36173 合并主仓,Rust 移植版进入主干
2026-07-23 InfoQ 英文报道发出,中文圈尚未跟进

7 月 23 日------InfoQ 发了英文报道,Hacker News 和 Reddit r/reactjs 都有热帖。中文内容几乎为零,这就是写这篇文章的理由。

二、React Compiler 是什么?为什么需要它?

如果你还没接触过 React Compiler,先搞清楚它解决什么问题。

手动 memoization 的痛苦

React 开发者对下面这段代码应该不陌生:

jsx 复制代码
import { useState, useMemo, useCallback } from 'react';

function TodoList({ todos }) {
  const [filter, setFilter] = useState('all');
  
  // 手动 memoization:每次写依赖数组都要小心翼翼
  const filteredTodos = useMemo(() => {
    return todos.filter(t => t.status === filter);
  }, [todos, filter]);

  const handleAdd = useCallback(() => {
    console.log('add todo');
  }, []);

  return (
    <div>
      <button onClick={handleAdd}>添加</button>
      {filteredTodos.map(t => (
        <div key={t.id}>{t.text}</div>
      ))}
    </div>
  );
}

useMemo、useCallback、React.memo------这三个 API 是 React 性能调优的"三板斧"。问题是:

  1. 心智负担大:每个变量都要想依赖数组写对没有
  2. 容易写错:漏一个依赖 → stale closure,多写一个 → 白跑
  3. 代码可读性差:逻辑被 hook 包了一层又一层
  4. 大多人干脆不写:反正不写也能跑,性能差一点而已

React Compiler 的目标就是让你不用再手动写 memoization。编译器在构建时自动分析组件依赖,自动插入缓存逻辑。

开启 Compiler 后,只需要这样写:

jsx 复制代码
import { useState } from 'react';

// 不写 useMemo、useCallback,干净利落
function TodoList({ todos }) {
  const [filter, setFilter] = useState('all');
  
  const filteredTodos = todos.filter(t => t.status === filter);

  const handleAdd = () => {
    console.log('add todo');
  };

  return (
    <div>
      <button onClick={handleAdd}>添加</button>
      {filteredTodos.map(t => (
        <div key={t.id}>{t.text}</div>
      ))}
    </div>
  );
}

代码更干净,性能不降反升------因为编译器能分析的维度比人手写依赖数组多得多。

三、为什么用 Rust 重写?

React Compiler 原本用 TypeScript 写的,跑在 Babel 上。功能没问题,但性能不够快。尤其大型项目(Next.js 企业应用动辄上千个组件),编译时间被 Compiler 拖长是常见抱怨。

Rust 版本的性能数据如下(来自 PR 描述和 Rspack 团队的基准测试):

场景 TS 版 → Rust 版 提升
Babel 插件模式总耗时 基准 → 快 3 倍 3x
核心转换逻辑(扣除序列化) 基准 → 快 10 倍 10x
Rspack 集成(SWC 原生) --- 7-13 倍

序列化瓶颈

Rust 版本在 Babel 插件模式下"只"快 3 倍,但核心转换逻辑快了 10 倍。差距主要来自跨语言 FFI 数据转换开销。

Babel 体系下 AST 是 JavaScript 对象,Rust 编译器需要把这些 JS 对象转换(Marshal)成 Rust 结构体才能处理,处理完再原路转换回去。这个数据编组(Marshal/Unmarshal)的过程占总耗时的 70% 左右,成了最大的性能瓶颈。

打个通俗的比方:Rust 编译器是一位超级快厨,但食材(Babel AST)得先完成"日译英"才能下锅,做完再"英译日"端给客人。翻译时间比颠勺炒菜还长。

这也是为什么原生集成(SWC、OXC、Rolldown)才是 Rust 版本真正的发力点------绕开 Babel 的跨语言 FFI 转换开销后,实测性能提升直接飙到 7-13 倍。

生产环境数据

这不是纸上谈兵的数据,React Compiler 已经在 Meta 的产品里跑了:

  • Instagram:首屏加载快 12%,交互响应快 2.5 倍
  • Meta Quest Store:类似提升
  • Sanity Studio:渲染时间降低 20-30%

四、架构拆解:不是重写,是逐 Pass 移植

Rust 版本和 TS 版本的架构完全相同,这不是重新设计,而是一次"逐 Pass 移植"。

Rust 版本与 TS 版本在编译流水线(Pipeline)和 Pass 设计上完全相同,是一次逐 Pass 移植;但在底层数据表示上,为了适配 Rust 所有权模型,Rust 版全面采用了 Arena + 索引模式,放弃了 GC 引用。

编译器内部流程

React Compiler 的核心流程分三步:

第一步:AST → HIR(高层中间表示)

编译器不直接操作 AST,而是先把 AST 转换成自己的中间表示 HIR(High-level Intermediate Representation)。HIR 使用控制流图(CFG)+ 静态单赋值(SSA)形式。

如果你不知道 CFG 和 SSA 是什么,简单来说:

  • CFG(控制流图):把代码的执行路径画成图,if/else、循环、异常都变成图的分支
  • SSA(静态单赋值):每个变量只赋值一次,再次修改等于创建新变量。这让数据流分析变得非常精确

这两个概念来自编译器经典理论,不是 React 发明的。Java 编译器、LLVM 都用这套。

第二步:多轮 Pass 分析

在 HIR 上,编译器跑多轮 Pass:

  • 依赖分析:哪些变量被哪些代码用到
  • 可变性问题检测:哪些值可能被修改
  • 自动 memoization 插入:决定哪些需要缓存

第三步:HIR → 代码生成

分析完后,生成最终代码(Babel AST 或目标格式)。

Rust 版的差异:Arena + 索引

架构相同,但数据表示做了调整。为了适配 Rust 的借用检查器(borrow checker),团队大量使用 arena 分配 + 索引模式。

简单来说:不用 Rust 的引用 &T 来指向数据,而是把所有数据放在一个连续内存池(arena)里,用整数索引来引用。这样做的原因是 Rust 的所有权模型在编译器这种"到处互相引用"的场景下会非常痛苦,arena + 索引绕开了这个痛点。

这是个务实的选择。不少 Rust 编译器项目(包括 rustc 自己)都采用类似模式。

公共 API:Babel AST 进、Babel AST 出

对外接口设计为"Rust Babel AST 进、Babel AST 出"。各集成方(Babel、OXC、SWC)负责在自己原生表示和这个中间格式之间做转换。

这意味着什么?不管你用什么构建工具,Compiler 的输出格式不变,集成方只需要处理 AST 转换层。

五、编译产物对比:Compiler 到底干了什么?

这是整篇文章最实在的部分。我跑了一个真实的编译对比,不是截图搬运。

原始代码(开启 Compiler 前)

上面那个 TodoList 组件,不经 Compiler 编译,输出如下:

js 复制代码
function TodoList(_ref) {
  var todos = _ref.todos;
  var filter = _ref.filter;
  
  var filteredTodos = (0, _react.useMemo)(function () {
    return todos.filter(function (t) {
      return t.status === filter;
    });
  }, [todos, filter]);  // ← useMemo 运行时调用
  
  var handleAdd = (0, _react.useCallback)(function () {
    console.log('add todo');
  }, []);  // ← useCallback 运行时调用
  
  // 每次渲染都重新创建 JSX
  return /*#__PURE__*/React.createElement("div", null, 
    /*#__PURE__*/React.createElement("button", { onClick: handleAdd }, "添加"), 
    filteredTodos.map(function (t) {
      return /*#__PURE__*/React.createElement("div", { key: t.id }, t.text);
    })
  );
}

可以看到,useMemo 和 useCallback 都保留了------它们是运行时 hook,依赖 React 的 hook 系统来工作。

编译后(开启 React Compiler)

同一个组件,经过 React Compiler 编译后:

js 复制代码
var _compilerRuntime = require("react/compiler-runtime");
var _react = require("react");

function TodoList(t0) {
  var $ = (0, _compilerRuntime.c)(10);  // ← 创建 10 个缓存槽
  var todos = t0.todos;
  
  // useState 调用保留,但 setFilter 被忽略(未使用就不解构出来)
  var _useState = (0, _react.useState)("all"),
      _useState2 = _slicedToArray(_useState, 1),
      filter = _useState2[0];
  
  // ① filteredTodos 的缓存逻辑
  var t1;
  if ($[0] !== filter || $[1] !== todos) {
    // 依赖变了,重新计算
    var _t;
    if ($[3] !== filter) {
      _t = function _t(t) { return t.status === filter; };
      $[3] = filter;
      $[4] = _t;
    } else {
      _t = $[4];  // filter 没变,复用回调
    }
    t1 = todos.filter(_t);
    $[0] = filter;
    $[1] = todos;
    $[2] = t1;  // 缓存结果
  } else {
    t1 = $[2];  // 依赖没变,直接用缓存
  }
  var filteredTodos = t1;
  
  // ② handleAdd 被提取到模块作用域(见下方 _temp)
  var handleAdd = _temp;
  
  // ③ button 元素也缓存了(sentinel = 首次创建标记)
  var t2;
  if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
    t2 = React.createElement("button", { onClick: handleAdd }, "添加");
    $[5] = t2;  // 首次创建,存起来
  } else {
    t2 = $[5];  // 后续渲染直接复用
  }
  
  // ④ map 结果也缓存
  var t3;
  if ($[6] !== filteredTodos) {
    t3 = filteredTodos.map(_temp2);  // _temp2 被提取到模块作用域
    $[6] = filteredTodos;
    $[7] = t3;
  } else {
    t3 = $[7];
  }
  
  // ⑤ 最外层 div 也缓存
  var t4;
  if ($[8] !== t3) {
    t4 = React.createElement("div", null, t2, t3);
    $[8] = t3;
    $[9] = t4;
  } else {
    t4 = $[9];
  }
  return t4;
}

// 提取到模块作用域的函数
function _temp2(t_0) {
  return React.createElement("div", { key: t_0.id }, t_0.text);
}
function _temp() {
  console.log('add todo');
}

产物分析:Compiler 做了 5 件事

1. 创建缓存池 $

c(10) 创建了 10 个缓存槽,用来存中间计算结果和 JSX 元素。组件每渲染一次,就检查这些缓存槽,看依赖有没有变。

2. 替代 useMemo

原来的 useMemo 变成了 $[0] !== filter || $[1] !== todos 的手动检查。逻辑一样:依赖变了就重算,没变就取缓存。但省掉了 React hook 的运行时开销。

3. 替代 useCallback

handleAdd 没有任何依赖,被直接提取成模块级函数 _temp。不管渲染多少次,同一个函数引用,不需要 useCallback 包了。

4. 缓存 JSX 元素

button 元素用 sentinel(哨兵值)标记首次创建,后续渲染直接复用。<div> 包裹层也是同理,只有 t3(map 结果)变了才重建。

5. 提取回调函数

.map() 的回调和 reduce 的回调被提取到模块作用域(_temp2、_temp),不再每次渲染都创建新的函数实例。

一句话总结 :useMemo、useCallback、React.memo 这三个 API 在 Compiler 开启后基本不需要手写了。编译器比人更清楚该缓存什么。

六、实战:怎么在项目里用?

方式一:Babel 插件(通用,所有 React 19+ 项目可用)

⚠️ 前置条件:请确保项目已升级至 React 19.0+,否则 Compiler 无法生效。React 18.x 及以下版本不兼容。

安装依赖:

bash 复制代码
npm install babel-plugin-react-compiler@1.0.0

在 Babel 配置里加插件:

js 复制代码
// babel.config.js
module.exports = {
  presets: ['@babel/preset-react'],
  plugins: [
    ['babel-plugin-react-compiler', { compilationMode: 'infer' }]
  ]
};

compilationMode: 'infer' 是默认模式,编译器自动决定哪些组件需要优化。也可以设为 'all' 强制所有组件都优化,或者 'annotation' 只优化标注了 "use memo" 的组件。

方式二:Vite + @vitejs/plugin-react

js 复制代码
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [
    react({
      babel: {
        plugins: [
          ['babel-plugin-react-compiler', { compilationMode: 'infer' }]
        ]
      }
    })
  ]
});

方式三:Next.js

js 复制代码
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    reactCompiler: true
  }
};
module.exports = nextConfig;

Next.js 16+ 内置了 React Compiler 支持,只需要一行配置。

方式四:ESLint 插件(强烈推荐配在一起用)

光开 Compiler 不够,还得装 ESLint 插件来提前发现不合规代码:

bash 复制代码
npm install eslint-plugin-react-compiler@19.1.0-rc.2
js 复制代码
// eslint.config.js
import reactCompiler from 'eslint-plugin-react-compiler';

export default [
  {
    plugins: {
      'react-compiler': reactCompiler
    },
    rules: {
      'react-compiler/react-compiler': 'warn'  // 警告级别,不阻塞构建
    }
  }
];

装完之后,ESLint 会在你写了不合规代码时直接报警。比如:

sql 复制代码
src/BadComponent.jsx
  18:31  warning  Hooks must always be called in a consistent order,
          and may not be called conditionally.

我把所有配置都实际跑了一遍,这些代码是验证过的,不是文档搬运。

七、Rules of React:哪些写法会让 Compiler 失效?

React Compiler 不是开了就万事大吉。它有一套**"Rules of React"**------组件必须遵守的规则。违反规则的组件,Compiler 要么跳过优化,要么产出有 bug 的代码。

规则一:不要在 render 中修改 state

jsx 复制代码
// ❌ 违规:render 中调用 setState
function Bad({ items }) {
  const [count, setCount] = useState(0);
  
  if (count === 0) {
    setCount(1);  // render 中改 state → 无限重渲染
  }
  
  return <div>{count}</div>;
}

正确做法:在事件处理或 useEffect 里改 state。

规则二:不要在 render 中修改 props

jsx 复制代码
// ❌ 违规:直接修改传入的 props
function Bad({ items }) {
  items.push({ id: 999, name: 'new' });  // 修改 props 引用
  return items.map(item => <div key={item.id}>{item.name}</div>);
}

正确做法:把 props 当只读的,需要修改就先复制一份。

规则三:Hooks 不能条件调用

jsx 复制代码
// ❌ 违规:条件里调 hooks
function Bad({ items }) {
  const [count, setCount] = useState(0);
  
  if (items.length > 0) {
    const [extra, setExtra] = useState(0);  // ← 条件 hook,被 ESLint 抓到
  }
  
  return <div>{count}</div>;
}

ESLint 会直接报错:

sql 复制代码
18:31  error  React Hook "useState" is called conditionally. 
              React Hooks must be called in the exact same order 
              in every component render

规则四:不要在 render 中修改 ref.current

jsx 复制代码
// ❌ 违规:render 中改 ref
function Bad() {
  const ref = useRef({ value: 0 });
  ref.current.value = computeSomething();  // render 中改 ref
  
  return <div>{ref.current.value}</div>;
}

正确做法:将 ref 的可变操作移至事件处理函数 或 useLayoutEffect 中(如果你必须读取布局信息)。如果仅仅是为了存储实例,初始化时在 useRef 的回调中完成即可。

规则五:副作用只能放在 useEffect 里

jsx 复制代码
// ❌ 违规:render 中执行副作用
function Bad({ userId }) {
  const [data, setData] = useState(null);
  
  // 不能在 render 中发请求
  fetch(`/api/user/${userId}`).then(r => r.json()).then(setData);
  
  return <div>{data?.name}</div>;
}

这个规则不是 React Compiler 新发明的------React 一直有这些规则,只是以前没 Compiler 的时候不遵守也不会立刻炸。Compiler 会假设你的组件遵守规则来做优化分析,不遵守的组件产出可能有 bug。

我的建议 :开 ESLint 插件 + compilationMode: 'infer'(默认模式),让 Compiler 自己决定哪些组件跳过。这样即使有老代码不合规,也不会被错误优化。

八、生态集成:Rust 版本的全家桶

Rust 版本合并主仓后,前端工具链全线跟进:

工具 状态 说明
Oxlint 1.70 ✅ 已发布 新增 react/react-compiler 规则
SWC ✅ 已合并 Rust crate v68.1 发布,原生支持
Rspack 2.1 🔄 Beta 内置 builtin:swc-loader 直接启用 Compiler
Rolldown / Vite 8 ✅ PR 合并 选项已暴露,Vite 8 正式支持
Next.js 🔄 Canary v16.3.0-canary.52 集成,预计 16.4 稳定

补充:Next.js 的 experimental.reactCompiler 在最新的 Canary 中已经默认启用了 Turbopack 的 Rust 原生通道 ,这意味着如果你用 Next.js 16+ 搭配 Turbopack,整个链路(解析、转译、编译)完全绕开了 Babel 和 JS,性能提升直接拉满到 13 倍(而不再是受限于 Babel 模式的 3 倍)

简单来说,如果你用 Vite 8 或 Rspack 2.1,原生集成后不需要走 Babel 序列化了------直接吃 Rust 速度。

九、123K 行代码大部分是 AI 写的------这说明了什么?

回到 PR 描述里那句话。Joseph Savona 直接说了:架构是人设计的,但大部分代码是 AI 生成的。

这不是随口一说,有具体做法:

  1. 人设计架构:HIR、CFG、SSA、arena 这套数据结构是人定的
  2. 人定测试策略:1725 个测试用例 100% 通过是硬指标
  3. 人定增量方案:不是一把梭重写,而是分 pass 逐步迁移
  4. AI 在约束下生成代码:有了架构、测试、约束,AI 来填实现

这个模式跟 Bun 用 Claude 在 11 天内把 53 万行 Zig 重写为 Rust 如出一辙。

有人可能担心"AI 写的代码靠谱吗"。这里关键在于:约束比代码更重要。当架构设计、测试用例、质量门槛都定好之后,AI 生成的代码必须通过所有测试才能合并。这比很多人写的代码还严格。

当然,也不能过度解读。这是编译器移植------一个架构清晰、测试完善的场景。不是所有项目都适合这种模式。但这个 PR 确实展示了"AI 辅助大型代码迁移"的一个标杆案例。

十、和你之前听过的 TS 7.0 是什么关系?

如果你读过 TypeScript 7.0 那篇(用 Go 重写编译器,速度暴增 10 倍),会发现 React Compiler Rust 移植是同一条故事线的第二集:

维度 TS 7.0 React Compiler Rust
重写前语言 TypeScript TypeScript
重写后语言 Go Rust
性能提升 ~10 倍 3-10 倍(Babel 模式 / 核心逻辑)
主导者 微软 Meta
AI 辅助 未披露 大部分代码 AI 生成
开发者影响 编译速度 不用再写 useMemo/useCallback

前端工具链核心引擎从 JavaScript 逃离,这不是一个趋势------这是两个已经落地的事实。Babel 可能是下一个(OXC 已经在做 Rust 版了)。

十一、总结

React Compiler 的 Rust 移植做了三件事:

  1. 编译器本体从 TS 换成 Rust------架构不变,性能 3-10 倍
  2. 生态全线适配------SWC、OXC、Rspack、Vite 8、Next.js 已就位
  3. 展示了 AI 辅助大型代码迁移的范式------人设计约束,AI 填代码

对开发者来说,最直接的影响是:useMemo、useCallback、React.memo 这三个 API 正在变成历史名词。编译器比人更清楚该缓存什么。

如果你用 React 19+,今天就可以开起来。配 ESLint 插件一起用,提前发现不合规代码。

sql 复制代码
前端工具链 Rust/Go 化进度:
  TypeScript 7.0     ✅ Go 重写,已发布
  React Compiler     ✅ Rust 移植,已合并主仓
  Babel              🔄 OXC(Rust 版)进行中
  Webpack            🔄 Rspack(Rust 版)已发布
  Rollup             🔄 Rolldown(Rust 版)进行中
  ESLint             🔄 Oxlint(Rust 版)已发布
  Prettier           🅾️ 暂无 Rust 版

相关面试题

Q1:React Compiler 的核心作用是什么?它替代了哪些手动 API?

答 :React Compiler 是一个构建时编译器,核心作用是自动分析组件依赖关系,自动插入 memoization 逻辑。它替代了手动写的 useMemo、useCallback 和 React.memo。开启后,开发者不需要再手写依赖数组和包裹函数,编译器会自动缓存计算结果、回调函数和 JSX 元素。

Q2:React Compiler 的编译流程分哪几步?HIR、CFG、SSA 各是什么?

答:编译流程分三步:

  1. AST → HIR:将 Babel AST 转换成编译器内部的高层中间表示(HIR)。HIR 使用控制流图(CFG)+ 静态单赋值(SSA)形式。CFG 把代码执行路径画成图,SSA 要求每个变量只赋值一次,使数据流分析更精确。
  2. 多轮 Pass 分析:在 HIR 上跑依赖分析、可变性检测、memoization 插入。
  3. HIR → 代码生成:分析完生成最终代码。

Q3:React Compiler 的缓存机制是怎么工作的?

答 :Compiler 为每个组件创建一个缓存池 $(通过 react/compiler-runtime 的 c(n) 函数),包含 N 个缓存槽。每个缓存槽存一个中间结果(计算值、回调函数、JSX 元素等)。渲染时检查缓存槽对应的依赖是否变化,变了就重算并存新值,没变就直接取缓存。对于无依赖的函数用 sentinel(哨兵值)标记首次创建后永久复用。这套机制比手写 useMemo 的依赖数组更精确,因为它能追踪到每个子表达式的依赖变化。

Q4:什么是"Rules of React"?违反了会怎样?

答 :Rules of React 是 React 组件必须遵守的规则,包括:不要在 render 中修改 state、不要修改 props、Hooks 不能条件调用、不要在 render 中修改 ref.current、副作用只能放在 useEffect 里。违反规则后,Compiler 可能跳过该组件的优化(bailout),或者产出有 bug 的代码。推荐配 eslint-plugin-react-compiler 插件,在编码阶段就发现违规。

Q5:React Compiler 的 Rust 版本和 TS 版本在架构上有什么区别?

答 :编译器先将 AST 转换为基于控制流图(CFG)的 HIR ,并在该 IR 中强制使用**静态单赋值(SSA)**形式,以此为基础进行多轮 Pass 分析,Rust 版是"逐 Pass 移植",不是重新设计。主要差异在数据表示:为了适配 Rust 的借用检查器,Rust 版大量使用 arena 分配 + 索引模式(把数据放在连续内存池里用整数索引引用),而不是用 Rust 的引用 &T。公共 API 设计为"Babel AST 进、Babel AST 出",各集成方负责自己原生表示和这个中间格式之间的转换。性能上,Babel 插件模式快 3 倍(受序列化开销限制),核心转换逻辑快 10 倍,原生集成(SWC/OXC)可达 7-13 倍。

相关推荐
卡布鲁5 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
孙启超5 天前
【AI开发之Rust】第 11 课:智能指针与内部可变性
开发语言·后端·rust
mikuyyds5 天前
geo-toolbox 水文插件算法解析:从 Muskingum 到 Muskingum-Cunge
算法·rust·gis
PC2005-cloud5 天前
Rust学习笔记:模块系统——mod、use、pub与多文件项目
rust
Amos_Web5 天前
Rspack 源码解析(十二):JavaScript Chunk 是如何被渲染出来的
前端·rust·源码
柯南46685 天前
【AI开发之Rust】第 14 课:网络请求与 JSON —— reqwest + serde
rust·编程语言
恋喵大鲤鱼5 天前
Rust 格式化输出占位符详解
rust
孙启超5 天前
【AI开发之Rust】第 13 课:async/await 与 tokio 异步运行时
开发语言·后端·rust
小道士写程序5 天前
Rust + Axum + MySQL + SQLx
rust