ระบุอายุการปิดสนิม
ฉันกำลังสร้างตัวดำเนินการ / เครื่องปฏิกรณ์ในขณะที่พบว่าปัญหานี้เป็นปัญหาตลอดชีวิต ไม่เกี่ยวข้องกับ async / Future และสามารถทำซ้ำได้โดยไม่ต้อง async sugar
use std::future::Future;
struct Runtime;
fn start_with_runtime<C, F>(closure: C)
where
C: for<'a> FnOnce(&'a Runtime) -> F,
F: Future
{
let rt = Runtime;
let _future = closure(&rt);
// block_on(future);
}
async fn async_main(_rt: &Runtime) {
// I can use _rt to do async stuff here
}
fn main() {
start_with_runtime(|rt| { async_main(rt) });
}
ฉันต้องการstart_with_runtime()รันในอนาคตและระบุการอ้างอิง async Runtime เป็นพารามิเตอร์
ไม่รวบรวม:
error: lifetime may not live long enough
--> src/main.rs:17:31
|
17 | start_with_runtime(|rt| { async_main(rt) });
| --- ^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
| | |
| | return type of closure is impl std::future::Future
| has type `&'1 Runtime`
ฉันคิดว่าปัญหานี้น่าจะเกิดจากการที่สนิมอนุมานอายุการใช้งานของการปิด:
https://github.com/rust-lang/rust/issues/58052 :
fn main() {
let f = |x: &i32| x;
let i = &3;
let j = f(i);
}
ไม่รวบรวมอย่างใดอย่างหนึ่ง:
error: lifetime may not live long enough
--> src/main.rs:2:23
|
2 | let f = |x: &i32| x;
| - - ^ returning this value requires that `'1` must outlive `'2`
| | |
| | return type of closure is &'2 i32
| let's call the lifetime of this reference `'1`
ดูเหมือนว่าลายเซ็นการปิดของฉันอนุมานได้ว่าเป็น|&'a Runtime| -> impl Future + 'bข้อผิดพลาดตลอดชีวิต ฉันรู้สึกว่าการให้ลายเซ็นที่ถูกต้องสำหรับการปิดจะช่วยได้ แต่ฉันจะให้ลายเซ็นที่ถูกต้องได้start_with_runtimeอย่างไร?
fn start_with_runtime<C>(closure: C)
where
C: for<'a> FnOnce(&'a Runtime) -> (impl Future + 'a),
ใช้ไม่ได้เพราะimpl Traitไม่ได้รับอนุญาตที่นี่
fn start_with_runtime<C,F>(closure: C)
where
C: for<'a> FnOnce(&'a Runtime) -> F,
F: Future + 'a
ไม่ทำงานเช่นกันเนื่องจาก'aไม่เป็นที่รู้จักนอกนิพจน์ HRTB
ใช้งานได้ถ้าฉันรู้ประเภท:
struct MyType<'a> {
_rt: &'a Runtime
}
fn start_with_runtime<C>(closure: C)
where
C: for<'a> FnOnce(&'a Runtime) -> MyType<'a>,
นี่เป็นเรื่องน่าเศร้าเมื่อคุณคิดมาตลอดชีวิต แต่ภาษาไม่ได้ให้วิธีแสดงสิ่งนี้ บางทีอาจมีเคล็ดลับในการเกิดสนิมเพื่อให้งานนี้?
คำตอบ
คำถามนี้ดูเหมือนจะมีสองคำถามที่แตกต่างกัน: สามารถแสดงความสัมพันธ์ที่ต้องการในไวยากรณ์ Rust ได้หรือไม่และจะใช้ได้กับการอนุมานประเภทการปิดหรือไม่
มาเริ่มอันแรกกันเลย คุณคิดถูกที่สิ่งนี้ไม่สามารถแสดงด้วยwhereอนุประโยคได้ ในการแสดงสิ่งนี้จำเป็นต้องเพิ่มลักษณะผู้ช่วยเหลือ
trait BorrowingFn<'a> {
type Fut: std::future::Future<Output = Something> + 'a;
fn call(self, arg: &'a Runtime) -> Self::Fut;
}
ที่ช่วยให้ขอบเขตที่เราต้องเขียนเป็น
C: for<'a> BorrowingFn<'a>,
และจัดเตรียมการใช้งานลักษณะนี้แบบครอบคลุมสำหรับฟังก์ชันที่เกี่ยวข้องทั้งหมด
impl<'a, Fu: 'a, F> BorrowingFn<'a> for F
where
F: FnOnce(&'a Runtime) -> Fu,
Fu: std::future::Future<Output = ()> + 'a,
{
type Fut = Fu;
fn call(self, rt: &'a Runtime) -> Fu {
self(rt)
}
}
( สนามเด็กเล่น )
ตกลงมันใช้งานได้กับฟังก์ชัน async แต่มันใช้งานได้กับการปิดที่ต้องการการอนุมานประเภทหรือไม่? น่าเสียดายที่คำตอบคือ "ไม่"
error: implementation of `BorrowingFn` is not general enough
--> src/main.rs:33:5
|
5 | / trait BorrowingFn<'a> {
6 | | type Fut: std::future::Future<Output = ()> + 'a;
7 | | fn call(self, arg: &'a Runtime) -> Self::Fut;
8 | | }
| |_- trait `BorrowingFn` defined here
...
33 | start_with_runtime(|rt| async_main(rt)); // however, it does not work with closure type inference :-(
| ^^^^^^^^^^^^^^^^^^ implementation of `BorrowingFn` is not general enough
|
= note: `[closure@src/main.rs:33:24: 33:43]` must implement `BorrowingFn<'0>`, for any lifetime `'0`...
= note: ...but `[closure@src/main.rs:33:24: 33:43]` actually implements `BorrowingFn<'1>`, for some specific lifetime `'1`
นี้จะถูกติดตามในสนิม lang / สนิม # 70263 คอมไพเลอร์ยังไม่ฉลาดพอที่จะสังเกตเห็นว่าการปิดนี้ต้องการประเภทที่มีอันดับสูงกว่า เพื่อความสนุกฉันพยายามรวบรวม-Z chalkใน Nightly แต่ยังไม่พร้อมสำหรับสิ่งนี้ (ข้อผิดพลาดของคอมไพเลอร์ภายใน)
ขออภัยนี่เป็นข้อ จำกัด ในภาษา คุณระบุอายุการใช้งานได้เฉพาะประเภทคอนกรีตเท่านั้น วิธีแก้ปัญหาอย่างหนึ่งคือการใช้ชนิดวัตถุลักษณะ
fn start_with_runtime<C, F, T>(closure: C)
where
C: for<'a> FnOnce(&'a Runtime) -> Pin<Box<dyn Future<Item = T> + Send + 'a>>,
{
let rt = Runtime;
let _future = closure(&rt);
// block_on(future);
}