跳转到内容
View in the app

A better way to browse. Learn more.

彼岸论坛

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.
欢迎抵达彼岸 彼岸花开 此处谁在 -彼岸论坛

[Rust] [Rust] 关于可变/不可变借用规则的求助(吐槽)一贴

发表于

背景: 正在给自己的小项目写 axum 全家桶的中间件.

代码片段:

/// Middleware for parsing and identifying Miku requests.
pub async fn miku_identification(request: AxumRequest, next: Next) -> Result<AxumResponse, ServerErrorExt> {
    let (
        Parts {
            method,
            uri,
            version,
            headers,
            mut extensions,
            ..
        },
        body,
    ) = request.into_parts();

    let queries = Queries::from_uri(&uri).unwrap_or_default();

    // * Parse and identify APP type
    if let Some(app_type) = AppTypeExt::get_from(&queries)? {
        extensions.insert(app_type);
    }

    // * Parse and identify UserInfo
    if let Some(user_info) = UserInfo::get_from(&queries)? {
        extensions.insert(user_info);
    }

    let mut request = AxumRequest::new(body);

    *request.method_mut() = method;
    *request.uri_mut() = uri;
    *request.version_mut() = version;
    *request.headers_mut() = headers;
    *request.extensions_mut() = extensions;

    Ok(next.run(request).await)
}

相信各位都能看出来我在干嘛, 但是一眼看上去是相当别扭, 便问为什么不这么写:

pub async fn miku_identification(mut request: AxumRequest, next: Next) -> Result<AxumResponse, ServerErrorExt> {
    let queries = Queries::from_uri(request.uri()).unwrap_or_default();

    // * Parse and identify APP type
    if let Some(app_type) = AppTypeExt::get_from(&queries)? {
        request.extensions_mut().insert(app_type);
    }

    // * Parse and identify UserInfo
    if let Some(user_info) = UserInfo::get_from(&queries)? {
        request.extensions_mut().insert(user_info);
    }

    Ok(next.run(request).await)
}

会 Rust 的一眼就能看出来, Queries::from_uri 的时候拿了不可变引用, 下面不能可变引用了.

但是我寻思着我也没改动 uri 啊, 改的是 extension 啊, 烦闷, 把 request break down into parts 吧:

/// Middleware for parsing and identifying Miku requests.
pub async fn miku_identification(request: AxumRequest, next: Next) -> Result<AxumResponse, ServerErrorExt> {
    let (
        Parts {
            method,
            uri,
            version,
            headers,
            mut extensions
        },
        body,
    ) = request.into_parts();

    // ...

    let mut request = AxumRequest::from_parts(Parts {
            method,
            uri,
            version,
            headers,
            extensions
        },
        body
     );

    Ok(next.run(request).await)
}

各位肯定一眼看出有问题, 因为 Parts 下面还有个私有字段 _priv: (), 想半天没想明白干嘛的, 阻止下游私自构建 Parts? 自然也没提供方法从现有的 method 等组装... 恼火至极, 只能写出文首那种别扭的玩意.

求问各位观众还有没有什么更好的写法.

Featured Replies

No posts to show

创建帐户或登录来提出意见

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.