代码之家  ›  专栏  ›  技术社区  ›  masonk

在创建该类型的线程局部变量的闭包中使用“来自外部函数的类型变量”

  •  0
  • masonk  · 技术社区  · 6 年前

    thread_local! 可由该工作线程上的任务使用的类型( T 在下面的例子中)。这个类的主要目的是 T型 不需要 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()
        }
    }
    

    ( Playground )

    不幸的是,我不能让我的代码打字检查时,我抽象了 T型 :

    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 ,然后我得到一个“shadowd type variable”错误。如果我介绍一种新的类型 U 呼叫 ,正好是我已经添加的地方。在我看来,第二件事就像编译器中的一个bug(如果你对此很好奇, here's the playground ).

    1 回复  |  直到 6 年前
        1
  •  5
  •   Francis Gagné    6 年前

    这与关闭无关,一切都与 static . 下面是一个产生相同错误的较小示例:

    fn foo<T>() {
        static BAR: Option<T> = None;
    }
    

    A 静止的 在泛型函数中,不会为每个 T ; 只有一个 变量。以以下程序为例:

    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>

    不幸的是,没有办法定义“泛型” “为每个 那是用过的。您可以做的是定义某种类型的typemap(即来自 TypeId Box<Any> )在地图上进行动态查找。