我正在尝试建立一个线程池,其中池中的每个线程都有一个thread_local!
类型,该线程可以由该工作线程上的任务使用。 (在下面的示例中为T
)。该类的主要目的是资源T
不必为Send
,因为它将通过 is {{1 }}。
我的用例是在Send
个数据库连接池上进行工作,但是我试图使其在资源类型!Send
上通用。
T
不幸的是,当我在extern crate threadpool;
use std::sync::mpsc::channel;
use std::sync::Arc;
// A RemoteResource is a threadpool that maintains a threadlocal ?Send resource
// on every pool in the thread, which tasks sent to the pool can reference.
// It can be used e.g., to manage a pool of database connections.
struct RemoteResource<T, M>
where
M: 'static + Send + Sync + Fn() -> T,
{
pool: threadpool::ThreadPool,
make_resource: Arc<M>,
}
impl<T, M> RemoteResource<T, M>
where
M: Send + Sync + Fn() -> T,
{
pub fn new(num_workers: usize, make_resource: M) -> Self {
RemoteResource {
pool: threadpool::ThreadPool::new(num_workers),
make_resource: Arc::new(make_resource),
}
}
pub fn call<F, R>(&mut self, f: F) -> R
where
R: 'static + Send,
F: 'static + ::std::marker::Send + FnOnce(&mut T) -> R,
{
let (tx, rx) = channel();
let maker = self.make_resource.clone();
self.pool.execute(move || {
use std::cell::RefCell;
thread_local!{
static UNSENDABLE_TYPE: RefCell<Option<T>> = RefCell::new(None)
}
UNSENDABLE_TYPE.with(|it| {
let mut mine = it.borrow_mut();
if mine.is_none() {
*mine = Some(maker());
}
if let Some(ref mut mine) = *mine {
let res = f(mine);
tx.send(res).unwrap();
return ();
}
unreachable!()
});
});
rx.recv().unwrap()
}
}
上抽象时,我的代码无法进行类型检查:
T
我尝试使用Rust编译器错误索引中的建议来解决此问题,但是“复制类型结束”不起作用。如果将“ error[E0401]: can't use type parameters from outer function
--> src/lib.rs:38:56
|
17 | impl<T, M> RemoteResource<T, M>
| - type variable from outer function
...
28 | pub fn call<F, R>(&mut self, f: F) -> R
| ---- try adding a local type parameter in this method instead
...
38 | static UNSENDABLE_TYPE: RefCell<Option<T>> = RefCell::new(None)
| ^ use of type variable from outer function
”复制到“ T
”中,则会收到“阴影类型变量”错误。如果我引入了新的类型call
,那么我会再次得到一个非常混乱的E401,但是这次建议我尝试将类型参数添加到U
的类型参数中,而这正是我实际所在的位置已经添加了。对我来说,第二件事看起来像是编译器中的错误。 (如果您对此感到好奇,请here's the playground)。
是否可以对此进行类型检查?如果没有,为什么不呢?
答案 0 :(得分:4)
它与闭包无关,与static
无关。这是一个产生相同错误的较小示例:
fn foo<T>() {
static BAR: Option<T> = None;
}
通用函数中的static
不会为每个T
生成一个静态值;只有一个static
变量。以下面的程序为例:
fn foo<T>() {
static mut COUNTER: i32 = 0;
unsafe {
COUNTER += 1;
println!("{}", COUNTER);
}
}
fn main() {
foo::<i32>();
foo::<u64>();
}
此打印:
1
2
在此,foo::<i32>
和foo::<u64>
共享相同的计数器。考虑到这一点,定义一个静态变量的类型取决于其封闭的泛型函数的类型参数是没有意义的,因为该函数可以被多次实例化。
不幸的是,无法定义为每个使用的static
实例化的“通用T
”。您可以做的是定义某种类型映射(即从TypeId
到Box<Any>
的映射)并在该映射中执行动态查找。