rust-lifetime-complex
3
总安装量
3
周安装量
#61045
全站排名
安装命令
npx skills add https://github.com/huiali/rust-skills --skill rust-lifetime-complex
Agent 安装分布
trae-cn
2
claude-code
2
codebuddy
2
trae
1
qoder
1
antigravity
1
Skill 文档
é«çº§çå½å¨æä¸ç±»åç³»ç»
æ ¸å¿é®é¢
为ä»ä¹è¿ä¸ªç±»å转æ¢å°±æ¯ç¼è¯ä¸è¿ï¼
ç±»åç³»ç»çè¾¹çå¾å¾åºä¹ææã
HRTB + dyn Trait Object å²çª
é®é¢ä»£ç
// â HRTB ä¸è½è£
è¿ dyn trait object
pub type ConnFn<T> =
dyn for<'c> FnOnce(&'c mut PgConnection) -> BoxFuture<'c, T> + Send;
let f = Box::new(move |conn: &mut PgConnection| -> BoxFuture<'_, i64> {
Box::pin(async { Ok(42) })
}) as Box<ConnFn<i64>>; // â "one type is more general than the other"
åå
- éå
æå
·ä½çå½å¨æ
'_ ConnFn<T>è¦æ±ä»»æçå½å¨æfor<'c>- å ·ä½ä¸è½èªå¨åæéç¨
è§£å³ï¼æ HRTB çå¨å½æ°è¾¹ç
// â
HRTB åªå¨è°ç¨ç¹ä½¿ç¨æ³å
impl Db {
pub async fn with_conn<F, T, Fut>(&self, f: F) -> Result<T, DbError>
where
F: for<'c> FnOnce(&'c mut PgConnection) -> Fut + Send,
Fut: Future<Output = Result<T, DbError>> + Send,
{
let mut conn = self.pool.acquire().await?;
f(&mut conn).await
}
}
使ç¨
db.with_conn(|conn| async move {
// è¿é 'c ç±è°ç¨æ¶ç¡®å®ï¼ä¸éè¦ dyn
sqlx::query("...").fetch_all(conn).await
}).await
GAT + dyn Trait Object
é®é¢ä»£ç
// â GAT ä¸è½å dyn Trait ä¸èµ·ç¨
trait ReportRepo: Send + Sync {
type Row<'r>: RowView<'r>; // â GAT
}
let repo: Arc<dyn ReportRepo> = ...; // â ç¼è¯é误
é误信æ¯
error[E0038]: the trait cannot be made into an object
because associated type `Row` has generic parameters
åå
dyn ReportRepoéè¦ç»ä¸å¤§å°Row<'r>对ä¸å'ræä¸å大å°- 对象å®å ¨è§åç¦æ¢
è§£å³ï¼å屿¶æ
// å
é¨ï¼GAT + åç¨ï¼é«æ§è½ï¼
trait InternalRepo {
type Row<'r>: RowView<'r>;
async fn query<'c>(&'c self) -> Vec<Self::Row<'c>>;
}
// å¤é¨ï¼owned DTOï¼å
¼å®¹ GraphQLï¼
pub trait PublicRepo: Send + Sync {
async fn query(&self) -> Vec<ReportDto>; // owned
}
// éé
å±
impl PublicRepo for PgRepo {
async fn query(&self) -> Vec<ReportDto> {
let rows = self.internal.query().await; // åç¨å
é¨
rows.into_iter().map(|r| r.to_dto()).collect()
}
}
æ¶æå¾
GraphQL Layer (éè¦ 'static)
â
PublicRepo Trait (owned)
â
Adapter (è½¬æ¢ borrowed â owned)
â
InternalRepo Trait (GAT, borrowed)
â
DB Implementation
‘static è¦æ±å²çª
åºæ¯
// async-graphql è¦æ± schema æ¯ 'static
// ä½ repo æ¹æ³è¿ååç¨æ°æ®
async fn resolve(&self) -> Result<&'r Row<'r>> {
// â 'r ä¸è½ outlive 'static
}
è§£å³ï¼owned æ°æ®
// ä¸è¦å¨ API 屿´é²åç¨
async fn resolve(&self) -> Result<ReportDto> {
let row = self.repo.query().await?; // owned
Ok(row.to_dto())
}
使¶ä¾å¤
- ä» å¨ éå¸¸çæ çåç¨ï¼å¦åæ¬¡å½æ°è°ç¨å ï¼
- å®å ¨æ§å¶ ææè ååç¨ççå½å¨æ
- æ§è½æ¶çæ¾è ä¸ä¸å¯æ¿ä»£
常è§å²çªæ¨¡å¼
| æ¨¡å¼ | å²çªåå | è§£å³ |
|---|---|---|
| HRTB â dyn | å ·ä½ vs éç¨ | æ³å彿°æ¿ä»£ dyn |
| GAT â dyn | 大å°ä¸åºå® | åå±è®¾è®¡ |
| ‘static + åç¨ | çå½å¨æçç¾ | owned æ°æ® |
| async + çå½å¨æ | åç¨ææç¶æ | drop åç¨æ owned |
| closure æè· + Send | çå½å¨æé®é¢ | å éæ ‘static |
使¶æ¾å¼åç¨
æ§è½ vs å¯ç»´æ¤æ§
// æ§è½æ¶ç vs 夿æ§
fn should_borrow() -> bool {
// å¤§æ°æ®ç»æ â åç¨
// é«é¢è®¿é® â åç¨
// çå½å¨æç®å â åç¨
// 夿çå½å¨æ â owned
// API è¾¹ç â owned
// 弿¥ä¸ä¸æ â owned
}
ç»éªæ³å
- API å±ï¼é»è®¤ owned
- å é¨å®ç°ï¼æéåç¨
- æ§è½çç¹ï¼èèåç¨
- å¤æåº¦é«æ¶ï¼éåå° owned
è°è¯æå·§
ç¼è¯å¨é误
| é误 | å«ä¹ |
|---|---|
| “one type is more general” | è¯å¾æå ·ä½è½¬éç¨ |
| “lifetime may not live long enough” | åç¨è¶ åºèå´ |
| “cannot be made into an object” | GAT + dyn ä¸å ¼å®¹ |
| “does not live long enough” | åç¨è¢«æåéæ¾ |
æ¹æ³
- æå°åï¼ååºæå°å¤ç°ä»£ç
- æ æ³¨çå½å¨æï¼æ¾å¼ååºææçå½å¨æ
- 鿥ç®åï¼å»ææ½è±¡ï¼ç´é¢é®é¢
- æ¥åç°å®ï¼ä¸æ¯ææè®¾è®¡é½è½ç¼è¯