You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Axum中克隆静态引用的嵌套值与克隆静态引用本身的行为差异疑问

Axum中克隆静态引用的嵌套值与克隆静态引用本身的行为差异疑问

嘿,这个问题其实戳中了Rust里引用克隆和结构体克隆的核心区别,我来给你掰扯清楚~

首先得抓住核心前提:你的ApiState里的settings是一个&'static Settings——也就是指向静态生命周期Settings实例的引用,这是分析两种写法差异的关键。

先看第一种写法:

pub async fn ui_settings(State(state): State<ApiState>) -> ApiResponse<UiSettings> {
    OK!(state.settings.api.ui.clone())
}

这里的执行逻辑是这样的:

  • state.settings是&Settings类型,访问它的api字段时,Rust会自动解引用这个引用,得到&ApiSettings(因为Settings的api字段是值类型)
  • 接着访问ui字段,得到&UiSettings
  • 最后调用clone(),因为UiSettings派生了Clone trait,这一步会克隆出一个全新的UiSettings实例,拿到它的所有权,刚好匹配返回类型的要求。

再看你写的第二种写法:

pub async fn ui_settings(State(state): State<ApiState>) -> ApiResponse<UiSettings> {
    let settings = state.settings.clone();
    OK!(settings.api.ui)
}

这里藏着一个很容易踩的Rust坑:

  • state.settings是引用类型,Rust会优先调用引用自身的Clone实现,而不是引用指向的Settings结构体的Clone实现。引用的Clone逻辑特别简单——就是返回当前引用的副本,说白了settings变量还是一个&'static Settings,和原来的引用完全指向同一个静态Settings实例。
  • 那settings.api.ui自然还是&UiSettings类型,这时候如果你的OK!宏要求传入UiSettings(毕竟返回类型是ApiResponse<UiSettings>),这段代码其实编译不通过,除非你给UiSettings也派生了Copy trait(但你代码里只加了Clone)。

如果咱们把第二种写法修正成真正克隆整个Settings结构体的版本:

let settings = (*state.settings).clone();
OK!(settings.api.ui)

这时候才是真的递归克隆了整个Settings结构体(包括嵌套的ApiSettings和UiSettings),然后返回其中的UiSettings字段。这时候和第一种写法的差异就很明显了:

  • 第一种写法只克隆最内层需要的UiSettings,开销极小
  • 修正后的第二种写法会克隆整个嵌套结构体,开销大很多,要是Settings里还有其他大字段,性能影响会更显著。

最后再给你划个重点:

  • 你现在写的第二种写法(没显式解引用的)和第一种写法完全不是一回事,甚至可能编译失败
  • 要是你想先克隆整个Settings再取字段,必须显式解引用后再克隆,这时候和第一种写法的核心差异就是克隆的范围不同,性能开销天差地别。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 12:00:31