Rust 如何存储引用而不必处理生存期?

Rust 如何存储引用而不必处理生存期?,rust,symbols,ffi,lifetime,Rust,Symbols,Ffi,Lifetime,正如所建议的,我收集了Symbols,而不是每次提取它们,但是Symbol需要一个生命周期。使用生存期会更改方法签名并破坏与方法的兼容性DynamicReload::update 使用std::mem::transmute将Symbol的生存期更改为'static,这是一种有效的解决方法吗 extern crate dynamic_reload; use dynamic_reload::{DynamicReload, Lib, Symbol, Search, PlatformName, Upd

正如所建议的,我收集了
Symbol
s,而不是每次提取它们,但是
Symbol
需要一个生命周期。使用生存期会更改方法签名并破坏与方法的兼容性
DynamicReload::update

使用
std::mem::transmute
Symbol
的生存期更改为
'static
,这是一种有效的解决方法吗

extern crate dynamic_reload;

use dynamic_reload::{DynamicReload, Lib, Symbol, Search, PlatformName, UpdateState};
use std::sync::Arc;
use std::time::Duration;
use std::thread;
use std::mem::transmute;

struct Plugins {
    plugins: Vec<(Arc<Lib>, Arc<Symbol<'static, extern "C" fn() -> i32>>)>,
}

impl Plugins {
    fn add_plugin(&mut self, plugin: &Arc<Lib>) {
        match unsafe { plugin.lib.get(b"shared_fun\0") } {
            Ok(temp) => {
                let f: Symbol<extern "C" fn() -> i32> = temp;
                self.plugins.push((plugin.clone(), Arc::new(unsafe { transmute(f) })));
            },
            Err(e) => println!("Failed to load symbol: {:?}", e),
        }
    }

    fn unload_plugins(&mut self, lib: &Arc<Lib>) {
        for i in (0..self.plugins.len()).rev() {
            if &self.plugins[i].0 == lib {
                self.plugins.swap_remove(i);
            }
        }
    }

    fn reload_plugin(&mut self, lib: &Arc<Lib>) {
        Self::add_plugin(self, lib);
    }

    // called when a lib needs to be reloaded.
    fn reload_callback(&mut self, state: UpdateState, lib: Option<&Arc<Lib>>) {
        match state {
            UpdateState::Before => Self::unload_plugins(self, lib.unwrap()),
            UpdateState::After => Self::reload_plugin(self, lib.unwrap()),
            UpdateState::ReloadFailed(_) => println!("Failed to reload"),
        }
    }
}

fn main() {
    let mut plugs = Plugins { plugins: Vec::new() };

    // Setup the reload handler. A temporary directory will be created inside the target/debug
    // where plugins will be loaded from. That is because on some OS:es loading a shared lib
    // will lock the file so we can't overwrite it so this works around that issue.
    let mut reload_handler = DynamicReload::new(Some(vec!["target/debug"]),
                                                Some("target/debug"),
                                                Search::Default);

    // test_shared is generated in build.rs
    match reload_handler.add_library("test_shared", PlatformName::Yes) {
        Ok(lib) => plugs.add_plugin(&lib),
        Err(e) => {
            println!("Unable to load dynamic lib, err {:?}", e);
            return;
        }
    }

    //
    // While this is running (printing a number) change return value in file src/test_shared.rs
    // build the project with cargo build and notice that this code will now return the new value
    //
    loop {
        reload_handler.update(Plugins::reload_callback, &mut plugs);

        if plugs.plugins.len() > 0 {
            let fun = &plugs.plugins[0].1;
            println!("Value {}", fun());
        }

        // Wait for 0.5 sec
        thread::sleep(Duration::from_millis(500));
    }
}
外部板条箱动态装载;
使用动态重新加载:{DynamicReload,Lib,Symbol,Search,PlatformName,UpdateState};
使用std::sync::Arc;
使用std::time::Duration;
使用std::线程;
使用std::mem::transmute;
结构插件{
插件:Vec插件。添加插件(&lib),
错误(e)=>{
println!(“无法加载动态库,错误{:?}”,e);
返回;
}
}
//
//在运行(打印数字)时,更改文件src/test_shared.rs中的返回值
//使用cargo build构建项目,请注意,此代码现在将返回新值
//
环路{
reload_handler.update(插件::reload_回调和mut插件);
如果plugs.plugins.len()大于0{
让乐趣=&plugs.plugins[0].1;
println!(“值{}”,fun());
}
//等待0.5秒
线程::睡眠(持续时间::从_毫秒(500));
}
}
由于
Symbol
没有实现
PartialEq
,因此我仍然必须将
Arc
保留在向量中

如何存储引用而不必处理生存期

98%的案例的答案是:你没有。使用寿命是生锈的最大原因之一。在编译时,生命期强制您的引用将始终引用有效的内容。如果您希望“忽略”生命周期,那么Rust可能不是实现特定设计的最佳语言。您可能需要选择不同的语言或设计

使用
std::mem::transmute
Symbol
的生存期更改为
'static
,这是一种有效的解决方法吗

extern crate dynamic_reload;

use dynamic_reload::{DynamicReload, Lib, Symbol, Search, PlatformName, UpdateState};
use std::sync::Arc;
use std::time::Duration;
use std::thread;
use std::mem::transmute;

struct Plugins {
    plugins: Vec<(Arc<Lib>, Arc<Symbol<'static, extern "C" fn() -> i32>>)>,
}

impl Plugins {
    fn add_plugin(&mut self, plugin: &Arc<Lib>) {
        match unsafe { plugin.lib.get(b"shared_fun\0") } {
            Ok(temp) => {
                let f: Symbol<extern "C" fn() -> i32> = temp;
                self.plugins.push((plugin.clone(), Arc::new(unsafe { transmute(f) })));
            },
            Err(e) => println!("Failed to load symbol: {:?}", e),
        }
    }

    fn unload_plugins(&mut self, lib: &Arc<Lib>) {
        for i in (0..self.plugins.len()).rev() {
            if &self.plugins[i].0 == lib {
                self.plugins.swap_remove(i);
            }
        }
    }

    fn reload_plugin(&mut self, lib: &Arc<Lib>) {
        Self::add_plugin(self, lib);
    }

    // called when a lib needs to be reloaded.
    fn reload_callback(&mut self, state: UpdateState, lib: Option<&Arc<Lib>>) {
        match state {
            UpdateState::Before => Self::unload_plugins(self, lib.unwrap()),
            UpdateState::After => Self::reload_plugin(self, lib.unwrap()),
            UpdateState::ReloadFailed(_) => println!("Failed to reload"),
        }
    }
}

fn main() {
    let mut plugs = Plugins { plugins: Vec::new() };

    // Setup the reload handler. A temporary directory will be created inside the target/debug
    // where plugins will be loaded from. That is because on some OS:es loading a shared lib
    // will lock the file so we can't overwrite it so this works around that issue.
    let mut reload_handler = DynamicReload::new(Some(vec!["target/debug"]),
                                                Some("target/debug"),
                                                Search::Default);

    // test_shared is generated in build.rs
    match reload_handler.add_library("test_shared", PlatformName::Yes) {
        Ok(lib) => plugs.add_plugin(&lib),
        Err(e) => {
            println!("Unable to load dynamic lib, err {:?}", e);
            return;
        }
    }

    //
    // While this is running (printing a number) change return value in file src/test_shared.rs
    // build the project with cargo build and notice that this code will now return the new value
    //
    loop {
        reload_handler.update(Plugins::reload_callback, &mut plugs);

        if plugs.plugins.len() > 0 {
            let fun = &plugs.plugins[0].1;
            println!("Value {}", fun());
        }

        // Wait for 0.5 sec
        thread::sleep(Duration::from_millis(500));
    }
}
transmute
是一把大锤,适用于各种好的和坏的想法和实现。我鼓励永远不要直接使用它,而是将它包装在一个抽象层中,以某种方式帮助您实施适当的限制,使特定的转换正确

如果您选择使用
transmute
,您将承担编译器以前承担的全部责任。由您来确保引用始终有效,否则您将调用未定义的行为,并且允许您的程序执行任何数量的非常糟糕的操作


对于您的特定情况,您可以使用在单个结构中保留“库”和“对库的引用”,以隐藏
符号的生存期。事实上,Rental将其用作激励示例,libloading支持dynamic_reload。看见
更多细节和陷阱

我并不乐观,因为这需要一个
&mut self
。在该方法调用期间,它很容易使所有现有引用无效

另见:


你为什么不把它们装箱?@Boiethios你是说ArcOh,对不起,我没有读过……的定义,非常感谢你的解释