Rust &引用;使用外部函数中的类型变量;在创建该类型的线程局部变量的闭包中

Rust &引用;使用外部函数中的类型变量;在创建该类型的线程局部变量的闭包中,rust,Rust,我正在尝试构建一个线程池,其中池中的每个线程都有一个线程\u local可由该工作线程上的任务使用的类型。(T在下面的示例中)。该类的主要用途是资源T不必是Send,因为它将通过工厂方法Send在每个工作线程上本地构造 我的用例是在池上工作!发送db连接,但我试图通过资源类型T使其通用 extern crate threadpool; use std::sync::mpsc::channel; use std::sync::Arc; // A RemoteResource is a thre

我正在尝试构建一个线程池,其中池中的每个线程都有一个
线程\u local可由该工作线程上的任务使用的类型。(
T
在下面的示例中)。该类的主要用途是资源
T
不必是
Send
,因为它将通过工厂方法
Send
在每个工作线程上本地构造

我的用例是在
池上工作!发送
db连接,但我试图通过资源类型
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()
    }
}
我尝试使用Rust编译器错误索引中的建议来解决这个问题,但是“复制类型”不起作用。如果将
T
复制到
call
,则会出现“shadowd type variable”错误。如果我引入了一个新的类型
U
,那么我又会得到一个非常混乱的E401,但这次建议我尝试在
call
上的类型参数中添加一个类型参数,这正是我实际添加它的地方。这第二件事在我看来像是编译器中的一个bug。(如果你对此感到好奇,)


有没有可能让这个进行打字检查?如果不是,为什么不呢?

它与闭包无关,而与
静态
有关。下面是一个产生相同错误的较小示例:

fn foo<T>() {
    static BAR: Option<T> = None;
}
这张照片是:

1
2
这里,
foo::
foo::
都共享同一个计数器。考虑到这一点,定义一个类型取决于其封闭泛型函数的类型参数的静态函数是没有意义的,因为该函数可以多次实例化


不幸的是,没有办法定义为所使用的每个
T
实例化的“通用
static
”。相反,您可以定义某种类型的类型映射(即从
TypeId
Box
)并在该映射中执行动态查找。

它与闭包无关,而与
静态
有关。下面是一个产生相同错误的较小示例:

fn foo<T>() {
    static BAR: Option<T> = None;
}
这张照片是:

1
2
这里,
foo::
foo::
都共享同一个计数器。考虑到这一点,定义一个类型取决于其封闭泛型函数的类型参数的静态函数是没有意义的,因为该函数可以多次实例化


不幸的是,没有办法定义为所使用的每个
T
实例化的“通用
static
”。相反,您可以定义某种类型的类型映射(即从
TypeId
Box
的映射),并在该映射中执行动态查找。

?发送
-它是;你只能说
?大小
。很高兴知道。为了清楚起见,我重新编写了。错误消息不正确-另请参见发送错误消息;你只能说
?大小
。很高兴知道。为了清楚起见,我重新编写了。错误消息不正确-另请参见通用函数中的static不会为每个
T
生成一个static-您知道原因吗?我四处打听,但我找不出任何具体原因;这似乎是一种单态化的形式。当一切都是静态构建时,这可能会起作用,但如果应用程序使用动态链接库,则可能会有同一变量的多个实例化。例如,板条箱A定义了一个通用的
静态
,但没有实例化它,然后板条箱B和C都为同一类型实例化了它。对于函数来说,这通常不是问题,因为我们(通常)不关心有两个相同的函数。谢谢这个奇妙的答案!非常感谢。@FrancisGagné在“正常”情况下不会也发生这种情况吗?两个分别定义一个
静态FOO
(即使来自同一个共享板条箱)的dylib难道不会有不同的内存地址吗?@Shepmaster如果你试图用静态lib和动态lib混合构建一个二进制文件,你最终会出现类似
错误:无法满足依赖关系,因此“std”只出现一次
,这意味着在实践中,我不认为两个dylib可以包含相同的板条箱(共享板条箱也必须是dylib)。通用函数中的一个static不会为每个
t
生成一个static-您知道为什么吗?我四处打听,但我找不出任何具体原因;这似乎是一种单态化的形式。当一切都是静态构建时,这可能会起作用,但如果应用程序使用动态链接库,则可能会有同一变量的多个实例化。例如,板条箱A定义了一个通用的
静态
,但没有实例化它,然后板条箱B和C都为同一类型实例化了它。对于函数来说,这通常不是问题,因为我们(通常)不关心有两个相同的函数。谢谢这个奇妙的答案!非常感谢。@FrancisGagné在“正常”情况下不会也发生这种情况吗?两个分别定义一个
静态FOO
(即使来自同一个共享板条箱)的dylib难道不会有不同的内存地址吗?@Shepmaster如果你试图用静态lib和动态lib混合构建一个二进制文件,你最终会出现类似
错误:无法满足依赖关系,因此“std”只出现一次
,这意味着在实践中,我不认为两个dylib可以包含相同的板条箱(共享板条箱也必须是dylib)。