use axum::{
http::{self, header::HeaderMap, HeaderValue, StatusCode},
response::{IntoResponse, Response},
routing::{get, post},
Json, Router,
};
tokio::task_local! {
static NUMBER: u32;
static HM: HeaderMap;
}
async fn headers(hs: HeaderMap) {
let hs = hs.clone();
HM.scope(hs, async move {
// 这里会有个报错说Option<&HeaderValue>的生命周期要大于入参c的生命周期,这种情况我怎么标注生命周期解决呢
let host = HM.with(|c: &HeaderMap| -> Option<&HeaderValue> { c.get("Host") });
println!("{:?}", HM);
})
.await;
}
1
共 18 条评论, 1 页
评论区
写评论了解了,clone 应该不会有很大问题,刚才我看到 HeaderValue 的内部 是一个 Bytes:
如果我没记错的话,bytes::Bytes 就是为了零拷贝解码设计的,自身依赖于引用计数,clone 应该会很便宜,它的 文档也有说 “A cheaply cloneable and sliceable chunk of contiguous memory.”。
--
👇
eric642: 这里我想的场景是:客户端调用-->a服务---->b服务。有一些请求头可能是需要从客户端一直透传,那么用locakkey存这些请求头或者其他业务无关的信息,而后在发送http请求的地方透传出去。http请求放到with里感觉不合适,也没法异步
--
👇
TinusgragLin: 说起来,为啥不直接把处理代码放到 LocalKey::with 的闭包当中?这应该就是这个 API 如此设计的初衷。
这里我想的场景是:客户端调用-->a服务---->b服务。有一些请求头可能是需要从客户端一直透传,那么用locakkey存这些请求头或者其他业务无关的信息,而后在发送http请求的地方透传出去。http请求放到with里感觉不合适,也没法异步
--
👇
TinusgragLin: 说起来,为啥不直接把处理代码放到 LocalKey::with 的闭包当中?这应该就是这个 API 如此设计的初衷。
说起来,为啥不直接把处理代码放到 LocalKey::with 的闭包当中?这应该就是这个 API 如此设计的初衷。
找了一下,发现这个是基于thread local的,thread local本身有无法拿到引用的限制 https://github.com/rust-lang/rfcs/pull/461#issuecomment-63542891
如果可以自己进行安全性保证的话,应该可以“做一个违背祖宗的决定”(雄凤山音):
看起来都不可避免的要进行内存拷贝
cloned可
我刚刚发现标准库就有一个
Option::cloned
可以用!--
👇
ggggjlgl: 谢谢,看起来干净多了,刚才怎么找都找不到隐去这个None的方式。
谢谢,看起来干净多了,刚才怎么找都找不到隐去这个None的方式。
@ggggjlgl 的回答可以稍微简化一下:
总之,我猜这个 LocalKey::with API 这么设计应该是有理由的。
从安全角度上考虑,如果你可以这么做,那么 LocalKey::with(f) 就有可能会返回一个对 task local 数据的引用,那你是不是可以把这个引用发到其他 task 上,那这个数据就不怎么 task local 了。
我的猜测是:
我们的这个闭包,类型是 for<'a> FnOnce(&'a A) -> Option<&'a B>,注意这个闭包函数的返回值类型是一个关于生命周期变量 'a 的函数。
再来看 LocalKey::with<R, F: FnOnce(&T) -> R>(..., f: F),这里 F 的类型是 for<'a> FnOnce(&'a T) -> R,注意这里的类型 R 一旦被确定,就是一个常量,并不是关于生命周期变量 'a 的函数。
大佬能不能就简单的修复楼主的问题让代码跑起来。。。
--
👇
ggggjlgl: ```rust // 我觉得这种应该没必要添加生命周期注释,让编译器自动推断就行吧。。。 use std::collections::HashMap;
fn main() { f() }
fn f() { let host:fn(&HashMap<i32, i32>) -> Option<&i32> = |c| c.get(&1); let mut x = HashMap::new(); x.insert(1, 6); println!("{:?}", host(&x).unwrap()); }
这个写法似乎不能解决问题,编译器还是报错
--
👇
全称量词是儿子: let host = HM.with(|c: &'a HeaderMap| -> Option<&'b HeaderValue> where 'a:'b { c.get("Host") });
你不要听信其他人说生命周期不重要,在rust中如果没学会生命周期的标注的话,基本寸步难行,如果你是之前写过go的人,那几乎生命周期的标注会无处不在,因为go的编程思维都是引用,然后循环嵌套结构体,只要最里层的结构体有一个引用的字段,则嵌套它的所有父结构体都需要标注这个生命周期,如果函数中还用到这个引用字段,那几乎每一层结构体的函数或者方法都需要标注这个生命周期,当然这些如果都熟悉,其实还是很容易的
let host = HM.with(|c: &'a HeaderMap| -> Option<&'b HeaderValue> where 'a:'b { c.get("Host") });