Rust &引用;相互冲突的要求”;作为参数传递给方法的迭代器项的生存期

Rust &引用;相互冲突的要求”;作为参数传递给方法的迭代器项的生存期,rust,lifetime,Rust,Lifetime,我正在尝试编译以下代码: use std::collections::HashMap; #[derive(PartialEq, Eq, Hash, Clone)] struct Key<'a> { v: &'a str } fn make_key_iter(s: &str) -> Box<Iterator<Item = Key>> { Box::new(s.split('.').map(|e| Key { v: e }

我正在尝试编译以下代码:

use std::collections::HashMap;

#[derive(PartialEq, Eq, Hash, Clone)]
struct Key<'a> {
    v: &'a str
}

fn make_key_iter(s: &str) -> Box<Iterator<Item = Key>> {
    Box::new(s.split('.').map(|e| Key { v: e }))
}

struct Node<'a> {
    children: HashMap<Key<'a>, Box<Node<'a>>>
}

impl<'a> Node<'a> {
    fn lookup<'b>(&self, mut iter: Box<Iterator<Item = Key<'b>>>) -> bool {
        match iter.next() {
            Some(key) => match self.children.get(&key) {
                             Some(node) => node.lookup(iter),
                             None => false
                         },
            None => true
        }
    }
}

fn main() {
    let s = "a.b.c.d".to_string();
    let iter = make_key_iter(s.as_slice());
    let node = Node { children: HashMap::new() };
    node.lookup(iter);
}
使用std::collections::HashMap;
#[派生(PartialEq、Eq、哈希、克隆)]
结构密钥盒{
框::新的(s.split('.').map(|e | Key{v:e}))
}
结构节点,框节点(&self,mut-iter:Box>>)->bool

真正让人困惑的是,编译器建议的签名完全无效,因为它使用了未定义的生存期。

我同意诊断不太理想。我建议将bug归档;也许那个建议者还不知道关联类型的生命周期

为了解决您的问题,我建议您使用您已经拥有的生命周期:

impl<'a> Node<'a> {
    fn lookup(&self, mut iter: Box<Iterator<Item = Key<'a>>>) -> bool { //'
        match iter.next() {
            Some(key) => match self.children.get(&key) {
                             Some(node) => node.lookup(iter),
                             None => false
                         },
            None => true
        }
    }
}
进一步阐述 下面是一个较小的示例,显示了相同的问题:

use std::collections::HashSet;

fn example<'a, 'b>(set: HashSet<&'a u8>, key: &'b u8) -> bool {
    set.contains(&key)
}

fn main() {}
使用std::collections::HashSet;
fn示例(集合:HashSet bool{
set.contains(&key)
}
fn main(){}

类似地,如果首先设置生命周期(
之间的关系,则有一个建议:由于装箱迭代器也是迭代器,因此可以将查找函数更改为

fn lookup<'b, I: Iterator<Item = Key<'b>>>(&self, mut iter: I) -> bool {
    match iter.next() {
        Some(key) => match self.children.get(&key) {
                         Some(node) => node.lookup(iter),
                         None => false
                     },
        None => true
    }
}
这肯定会让编译器感到高兴。但这并不是您真正想要的!它会不必要地限制您可以用作查找参数的字符串片集。这样,您只能使用引用至少与
'a
所引用的作用域寿命相同的内存的字符串片。但对于查找,则不会实际上不需要他的限制

解决方案是完全去掉HashMap的
get
函数的类型参数
Q
中的任何生存期参数,而不是使用
Q=Key{
v:&'a街
}
对于str,impl>{
fn从键{
键{v:s}
}
结构节点,长方体节点{
设n=Node{children:HashMap::new()};
e、 插入(方框::新(n))
}
已占用(e)=>{
e、 进入_mut()
}
};
增加(i)项;
}
}
fn查找\u str(&self,s:&str)->bool{
self.lookup_iter(s.split('.').map(str_-to_键))
}
fn查找\u iter>{
如果让一些(键)=i.next(){
匹配self.children.get(键v){
一些(节点箱参考)=>节点箱参考查找(i),
无=>false
}
}否则{
真的
}
}
}
fn main(){

let mut node:node我不明白为什么我需要在这里将
'b
'a
联系起来。在
节点
实例中,没有对
iter
或其中任何项目的引用。为什么对
iter
的生命周期来说,这还不够,而这些项目仅仅是
查找
本身的范围呢?还有,accor丁托,
`b:`a
意味着b比a活得长,而不是相反。所以说这类似于说用于查找的键保证比节点活得长,但事实并非如此。呃。我每次谈到它时都会混淆,谢谢你的更正。我在回答中添加了更多的说明,也许不是这有助于解释一点吗?谢谢你的解释。“类型也包括寿命”是我所缺少的关键洞见。然而,我必须承认,我发现结果令人困惑。真的没有办法看一个容器是否包含一个与容器寿命一样长的密钥吗?这不是相当有限吗?还有,关键是什么“矛盾的要求”编译器说了吗?谢谢你的解释。我怀疑我仍然有点模糊,确切地说,<代码> <代码>在这里。考虑这个代码(修改)。playpen:。很明显,迭代器及其项的寿命没有
节点
实例的寿命长,这就是我认为
'a
所表示的。但这是编译的。我忽略了什么?@Ray:我不确定我是否理解这个问题。但我几乎可以肯定,这个playpen代码片段并不是你真正想要的。我刚刚意识到你想要的是什么实际上,您正在尝试实现这一点。让我稍后再与您联系。@Ray:请看一下我更新的答案。我认为,它应该可以很好地解决您的问题——也就是说,只要您仍然希望使用哈希映射存储对字符串片段的引用(这肯定会导致您达到这种复杂程度)非常感谢,@sellibitze!我已经接受了答案。不过,我确实对你的最后一句话有一个问题。似乎你是在暗示有一个更好的设计可以避免复杂性。是吗?FWIW,我提供的
Key
定义过于简单,用于说明。真正的
Key
enum Key{a(String),B(String)}
我希望使用与
&str
等效的东西进行查询(我不知道这是否可行)@Ray:如果你用
HashMap
存储
String
键而不是
&str
键,事情会自动变得更简单,约束也会更少,代价是为所有
字符串
s'缓冲区额外分配。多亏了
借用
你仍然可以通过
get
。因此,对于查找,您仍然可以从字符串切片中获益,避免不必要的字符串分配。
use std::collections::HashSet;

fn example<'a, 'b>(set: HashSet<&'a u8>, key: &'b u8) -> bool {
    set.contains(&key)
}

fn main() {}
fn lookup<'b, I: Iterator<Item = Key<'b>>>(&self, mut iter: I) -> bool {
    match iter.next() {
        Some(key) => match self.children.get(&key) {
                         Some(node) => node.lookup(iter),
                         None => false
                     },
        None => true
    }
}
fn lookup<I: Iterator<Item = Key<'a>>>(&self, mut iter: I) -> bool { //'
    match iter.next() {
        Some(key) => match self.children.get(&key) {
                         Some(node) => node.lookup(iter),
                         None => false
                     },
        None => true
    }
}
impl<'a> BorrowFrom<Key<'a>> for str {
    fn borrow_from<'s>(owned: &'s Key<'a>) -> &'s str {
        owned.v
    }
}
fn lookup_iter<'b, I: Iterator<Item = Key<'b>>>(&self, mut i: I) -> bool {
    if let Some(key) = i.next() {
        match self.children.get(key.v) {
            Some(node_box_ref) => node_box_ref.lookup_iter(i),
            None => false
        }
    } else {
        true
    }
}
#![feature(core)]
#![feature(hash)]
#![feature(std_misc)]
#![feature(collections)]

use std::collections::HashMap;
use std::collections::hash_map::Entry::{ Occupied, Vacant };
use std::borrow::BorrowFrom;

#[derive(PartialEq, Eq, Hash, Clone)]
pub struct Key<'a> {
    v: &'a str
}

impl<'a> BorrowFrom<Key<'a>> for str {
    fn borrow_from<'s>(owned: &'s Key<'a>) -> &'s str {
        owned.v
    }
}

fn str_to_key(s: &str) -> Key { 
    Key { v: s }
}

struct Node<'a> {
    children: HashMap<Key<'a>, Box<Node<'a>>>
}

impl<'a> Node<'a> {
    fn add_str(&mut self, s: &'a str) {
        self.add_iter(s.split('.').map(str_to_key))
    }

    fn add_iter<I>(&mut self, mut i: I) where I: Iterator<Item = Key<'a>> { //'
        if let Some(key) = i.next() {
            let noderef =
                match self.children.entry(key) {
                    Vacant(e) => {
                        let n = Node { children: HashMap::new() };
                        e.insert(Box::new(n))
                    }
                    Occupied(e) => {
                        e.into_mut()
                    }
                };
            noderef.add_iter(i);
        }
    }

    fn lookup_str(&self, s: &str) -> bool {
        self.lookup_iter(s.split('.').map(str_to_key))
    }

    fn lookup_iter<'b, I>(&self, mut i: I) -> bool where I: Iterator<Item = Key<'b>> {
        if let Some(key) = i.next() {
            match self.children.get(key.v) {
                Some(node_box_ref) => node_box_ref.lookup_iter(i),
                None => false
            }
        } else {
            true
        }
    }
}

fn main() {
    let mut node: Node<'static> = Node { children: HashMap::new() }; //'
    node.add_str("one.two.three");
    { // <-- "inner scope"
        let s = String::from_str("one.two.three");
        println!("lookup: {:?}", node.lookup_str(&*s));
    }
    println!("The End");
}