以下代码:
let conversation_model =
if lsm { CONVMODEL.lock().await } else {
conv_model_loader()
};CONVMODEL.lock().await是MutexGuard<T>,conv_model_loader()是T
我需要这两个的通用接口,所以我不能复制粘贴我的代码在两种情况下,因为它将只有不同的类型,任何其他都是一样的。
编辑:
有密码..。(至少我想做的事)
let (locked, loaded); // pun not intended
if lsm {
locked = CONVMODEL.lock().await;
} else {
loaded = conv_model_loader();
};
let mut chat_context = CHAT_CONTEXT.lock().await;
task::spawn_blocking(move || {
let conversation_model = if lsm { &*locked } else { &loaded };但我很生气是因为
use of possibly-uninitialized variable: `locked`\nuse of possibly-uninitialized `locked`因此,问题是如何使用MutexGuard与接口&T,但如何在spawn_blocking内部使用它,以及如何使用#[async_recursion]
编辑:
let (mut locked, mut loaded) = (None, None);
if lsm {
locked = Some( CONVMODEL.lock().await );
} else {
loaded = Some( conv_model_loader() );
};
let mut chat_context = CHAT_CONTEXT.lock().await;
task::spawn_blocking(move || {
let (lock, load);
let conversation_model =
if lsm {
lock = locked.unwrap();
&*lock
} else {
load = loaded.unwrap();
&load
};下面的代码正在工作,但实际上非常难看的XD (我想知道是否有可能简化这段代码)
发布于 2021-10-07 09:17:00
每当您对某个值有一些选择时,您都希望访问enum。例如,在铁锈中,我们不做像let value: T; let is_initialized: bool;这样的事情,我们做Option<T>。
您可以选择两个值,要么是已获得的互斥量,要么是直接值。这通常被称为“任一个”,并且有一个流行的锈菌箱包含这种类型:Either。对你来说,这看起来可能是:
use either::Either;
let conv_model = if lsm {
Either::Left(CONVMODEL.lock().await)
} else {
Either::Right(conv_model_loader())
};
tokio::task::spawn_blocking(move || {
let conversation_model = match &conv_model {
Either::Left(locked) => locked.deref(),
Either::Right(loaded) => loaded,
};
conversation_model.infer();
});这个类型以前存在于标准库中,但由于它不经常被使用,所以它被删除了,因为创建一个更具有描述性的特定域类型是相当微不足道的。我同意这一点,你可以这样做:
pub enum ConvModelSource {
Locked(MutexGuard<'static, ConvModel>),
Loaded(ConvModel),
}
impl Deref for ConvModelSource {
type Target = ConvModel;
fn deref(&self) -> &Self::Target {
match self {
Self::Locked(guard) => guard.deref(),
Self::Loaded(model) => model,
}
}
}
// ...
let conv_model = if lsm {
ConvModelSource::Locked(CONVMODEL.lock().await)
} else {
ConvModelSource::Loaded(conv_model_loader())
};
tokio::task::spawn_blocking(move || {
conv_model.infer();
});这是更有表现力的,并将“如何填充这个”从它使用的地方移开。
在常见情况下,您确实希望使用user4815162342展示的更简单的方法。您将存储其中一个临时成员,形成对它的引用(知道您刚刚初始化它),并将其交回。
然而,这并不适用于spawn_blocking。引用的生命周期是暂时的--将这样的引用传递给生成的任务是一个悬空的引用。
这就是为什么错误消息(“借来的值活得不够长”和“参数要求locked是为'static借来的”)引导您沿着试图将locked和loaded移动到闭包以位于其最后休息位置的路径,然后形成一个引用。那推荐信就不会悬空了。
但这意味着您将一个可能未初始化的值移到闭包中。铁锈不明白您正在使用相同的检查来查看填充了哪个临时值。(您可以想象第二次检查!lsm时会出现错误,现在切换到了。)
最终,您必须将值的来源移到生成的任务(闭包)中,以便形成具有可用生存期的引用。enum的使用基本上是对您的布尔案例进行编码,检查一些Rust理解的内容,并将其自然展开。
发布于 2021-10-07 07:48:20
您可以从两者中提取&mut T并使用它。下面这样的东西应该能起作用:
let (locked, loaded); // pun not intended
let conversation_model = if lsm {
locked = CONVMODEL.lock().await;
&mut *locked
} else {
loaded = conv_model_loader();
&mut loaded
};https://stackoverflow.com/questions/69477156
复制相似问题