对象的构造会分配该对象生命周期所需的数据,但还会创建另一个需要保留对数据的引用的对象:
pub fn new() -> Obj {
let data = compute();
Obj {
original: data,
processed: AnotherObj {
reference: &data
}
}
}
Run Code Online (Sandbox Code Playgroud)
是否可以用Rust的术语表达这一点?
在这里,我想要Obj,AnotherObj并且data拥有相同的生命周期,当然还没有new()通话。
此代码正确编译.它有一些未使用的代码警告,但现在没问题.
use std::collections::BTreeMap;
enum Object<'a> {
Str(String),
Int(i32),
Float(f32),
Vector(Vec<&'a Object<'a>>),
Prim(fn(State) -> State)
}
struct State<'a> {
named: BTreeMap<String, &'a Object<'a>>,
stack: Vec<Object<'a>>
}
impl<'a> State<'a> {
fn push_int(&mut self, x: i32) {
self.stack.push(Object::Int(x));
}
}
fn main() {
println!("Hello, world!");
let obj = Object::Str("this is a test".to_string());
}
Run Code Online (Sandbox Code Playgroud)
这段代码的重要部分是push_int和stack: Vec<Object<'a>>.
我正在尝试制作基于堆栈的VM.我想将状态传递给函数,函数可以从堆栈中取出东西,操作东西,然后将一些东西放回堆栈; 命名字段将保存命名对象.
我有一种预感,将堆栈表示为Vec<&'a Object<'a>>替代会更好.我现在拥有它的方式,我担心我会犯一些效率低下的错误.我的预感是正确的吗?
问题的第二部分是我不知道如何使引用版本的矢量工作.以适当的生命周期创建新值以推入堆栈对我来说不起作用.
我对这个问题有点模糊,所以如果我一直不清楚,请问我问题以清除问题.
我是 Rust 的新手,我正在尝试实现一个简单的、线程安全的内存键值存储,HashMap在RwLock. 我的代码如下所示:
use std::sync::{ Arc, RwLock, RwLockReadGuard };
use std::collections::HashMap;
use std::collections::hash_map::Iter;
type SimpleCollection = HashMap<String, String>;
struct Store(Arc<RwLock<SimpleCollection>>);
impl Store {
fn new() -> Store { return Store(Arc::new(RwLock::new(SimpleCollection::new()))) }
fn get(&self, key: &str) -> Option<String> {
let map = self.0.read().unwrap();
return map.get(&key.to_string()).map(|s| s.clone());
}
fn set(&self, key: &str, value: &str) {
let mut map = self.0.write().unwrap();
map.insert(key.to_string(), value.to_string());
}
}
Run Code Online (Sandbox Code Playgroud)
到目前为止,这段代码工作正常。问题是我正在尝试实现一个scan()函数,该函数返回一个Cursor可用于迭代所有记录的对象。我希望Cursor对象持有一个RwLockGuard,它在游标本身被释放之前不会被释放(基本上我不想在游标处于活动状态时允许修改)。
我试过这个:
use ...
type …Run Code Online (Sandbox Code Playgroud) 我试图返回一个包含对共享互斥体的引用的结构:
struct Test<'a> {
mutex: Arc<Mutex<()>>,
guard: &'a MutexGuard<'a, ()>,
}
impl<'a> Test<'a> {
pub fn new() -> Self {
let mutex = Arc::new(Mutex::new(()));
let guard = &mutex.lock().unwrap();
Self {
mutex,
guard,
}
}
}
Run Code Online (Sandbox Code Playgroud)
生命周期似乎是正确的:互斥体至少在 的生命周期内存在Test,因此MutexGuard没有对互斥体的停滞引用。但 Rust 给出了错误。如何向 Rust 解释字段的生命周期mutex足够长,可以guard正常工作?
cannot return value referencing local variable `mutex`
returns a value referencing data owned by the current function
Run Code Online (Sandbox Code Playgroud)
顺便说一句,我正在尝试创建一个“mutli-mutex” - 一组键的互斥体(如 中所示HashMap),以阻止下载名称在 hashmap 中的文件(因为它已经在下载)。
我有以下数据结构(简化):
use std::collections::HashMap;
pub struct StringCache {
// the hashmap keys point to elements stored in `storage`
// so never outlive this datastructure. the 'static refs are never handed out
table: HashMap<&'static str, usize>,
storage: Vec<Box<str>>,
}
Run Code Online (Sandbox Code Playgroud)
关于此处引用的生命周期向 Rust“撒谎”是合法/定义的行为吗?对我来说,这感觉就像违反了类型系统。这个数据结构的公共API健全吗?为了完整起见,以下是完整的实现:
use std::mem::transmute;
impl StringCache {
pub fn intern(&mut self, entry: &str) -> usize {
if let Some(key) = self.table.get(entry) {
return *key;
}
let idx = self.storage.len();
self.storage.push(entry.to_owned().into_boxed_str());
// we cast our refs to 'static here.
let key = …Run Code Online (Sandbox Code Playgroud) 我有两个对象,第二个对象要求第一个对象比它更长,因为它包含对第一个对象的引用.我需要将它们都移动到一个线程中,但编译器抱怨第一个没有足够长的时间.这是代码:
use std::thread;
trait Facade: Sync {
fn add(&self) -> u32;
}
struct RoutingNode<'a> {
facade: &'a (Facade + 'a),
}
impl<'a> RoutingNode<'a> {
fn new(facade: &'a Facade) -> RoutingNode<'a> {
RoutingNode { facade: facade }
}
}
fn main() {
struct MyFacade;
impl Facade for MyFacade {
fn add(&self) -> u32 {
999u32
}
}
let facade = MyFacade;
let routing = RoutingNode::new(&facade);
let t = thread::spawn(move || {
let f = facade;
let r = routing;
});
t.join(); …Run Code Online (Sandbox Code Playgroud) 我拥有Engine它,Worker并且我想Engine提供一些 API 作为Worker对特征的引用。API 实现是使用 分配Box并由 拥有的Engine,因此只要工作进程还活着,对它的引用就是稳定且有效的。
但我不明白如何用 Rust 表达它。
我已阅读为什么不能在同一结构中存储值和对该值的引用?我明白为什么我不能传递对拥有价值的引用。但是,就我而言,我传递的不是对拥有值本身的引用,而是对装箱值的引用,该值不会被移动,因此对它的引用必须是稳定的。
这是非工作原型:
trait EngineApi {
fn foo(&self);
}
struct Worker<'a> {
api: &'a EngineApi,
}
impl<'a> Worker<'a> {
fn new(engine_api: &'a EngineApi) -> Self {
Worker { api: engine_api }
}
}
struct Api;
impl EngineApi for Api {
fn foo(&self) {}
}
struct Engine<'a> {
api: Box<Api>,
worker: Box<Worker<'a>>,
}
impl<'a> Engine<'a> {
fn new() -> …Run Code Online (Sandbox Code Playgroud) 是否可以在映射中插入一个结构,其中键由插入的值所拥有?
在C中使用哈希映射时,这是我以前做过的事情.
伪代码示例:
struct MyStruct {
pub map: BTreeMap<&String, StructThatContainsString>,
// XXX ^ Rust wants lifetime specified here!
}
struct StructThatContainsString {
id: String,
other_data: u32,
}
fn my_fn() {
let ms = MyStruct { map: BTreeMap::new() };
let item = StructThatContainsString {
id: "Some Key".to_string(),
other_data: 0,
}
ms.insert(&item.id, item);
}
Run Code Online (Sandbox Code Playgroud)
如何正确处理这种情况?
如果这是不可能的,可以反过来做,其中值持有对密钥的引用,这将是一个String?
另一种方法是使用a set而不是a map,然后将整个存储struct为键,但在比较时只使用其中一个值(似乎它可以工作,但如果你想比较struct其他上下文,可能会适得其反).
我需要定义一个二叉搜索树,其中每个节点都可以访问父节点:
enum Tree<'a> {
Leaf,
Node {
left: Box<Tree<'a>>,
right: Box<Tree<'a>>,
parent: &'a Tree<'a>,
data: u64,
}
}
impl <'a> Tree<'a> {
pub fn new(data: u64, parent: &'a Tree) -> Tree<'a> {
Tree::Node {
left: Box::new(Tree::Leaf),
right: Box::new(Tree::Leaf),
parent,
data
}
}
pub fn insert_at_left_leaf(&'a mut self, data: u64) {
match *self {
Tree::Leaf => panic!("Leaf has no children"),
Tree::Node {ref mut left, ..} => {
**left = Tree::new(data, self);
}
}
}
}
fn main() {
let parent = …Run Code Online (Sandbox Code Playgroud) 以下代码无法编译:
use std::str::Chars;
struct Chunks {
remaining: Chars,
}
impl Chunks {
fn new(s: String) -> Self {
Chunks {
remaining: s.chars(),
}
}
}
Run Code Online (Sandbox Code Playgroud)
错误是:
use std::str::Chars;
struct Chunks {
remaining: Chars,
}
impl Chunks {
fn new(s: String) -> Self {
Chunks {
remaining: s.chars(),
}
}
}
Run Code Online (Sandbox Code Playgroud)
Chars不拥有要迭代的字符,也不能超过其&str或String从其创建的字符。
是否存在Chars不需要生存期参数的私有版本,或者我必须自己保留Vec<char>和索引?