2017-06-18 26 views
0

我有一个恒定的形式定义的阵列,任何函数外:迭代查找,临时值下降,同时仍然借

const VALUES: [(char, &str); 2] = [('A', "abc"), ('B', "acb")]; 

我试图使用find()方法位于Iterator,在为了从一个基于谓词的数组中提取单个元素:

VALUES.iter().find(|&&(name, _)| name == 'A'); 

在这种形式下,它工作正常。但是,我无法将找到的元素评估为任何内容,因为只要我尝试创建绑定,尝试绑定结果,根据文档应该返回为Option<T>

让我们改变第二行是不工作:

const VALUES: [(char, &str); 2] = [('A', "abc"), ('B', "acb")]; 

fn main() { 
    let result = VALUES.iter().find(|&&(name, _)| name == 'A'); 
} 

Playground

人们会想到这个返回Option<T>作为根据文档,而是我回来编译错误:

error: borrowed value does not live long enough 
--> src/main.rs:4:63 
    | 
4 |  let result = VALUES.iter().find(|&&(name, _)| name == 'A'); 
    |     ------ temporary value created here  ^temporary value dropped here while still borrowed 
5 | } 
    | - temporary value needs to live until here 
    | 
    = note: consider using a `let` binding to increase its lifetime 

我完全困惑;我确定我刚刚与“借阅检查器”搞混了。也许有人可以指出我正确的方向?

回答

2

问题出在您将该数组转换为迭代器的特定方式。

首先,Rust中的const实际上并不存在于任何地方。相反,他们在任何地方都被价值取代。所以每次你使用一个常量,你都会得到一个新的副本。其次,你正在使用IntoIterator::into_iter。这需要的值并将其转换为迭代器。

这些结合第三部分:IntoIterator而不是实现了固定大小的数组。它只适用于指针固定大小的数组。因此,为了调用into_iter,编译器必须插入调用者的自动借用。

那么,什么是实际发生的情况是这样的:

let t = { 
    // Make a new copy of `VALUES`. 
    let values: [(char, &str); 5] = VALUES; 
    // Borrow it. 
    let values: &[_] = &values; 
    // Call `into_iter` on the borrow. 
    IntoIterator::into_iter(values).find(|&&(name, _)| name == 'A') 
}; 

这会导致问题,因为编译器必须同时复制为了得到一个迭代器借用VALUES。像所有临时人员一样,所述复制只在陈述时才存在,但借用(通过绑定到变量)必须比这更长寿。

最好的解决办法是将VALUES一个指针给数组。这可以防止复制整个数组;相反,您只能在每次使用时复制指针。

const VALUES: &[(char, &str)] = &[...]; 

或者,你可以明确地做出VALUES副本,并将其存储在一个变量,然后在使用into_iter。但是,像以前一样,这会引入不必要的复制。

+0

Const数组实际存在于内存中。 [此代码](https://play.rust-lang.org/?gist=023a4c4ea0cc8cac7a890bbd3a05d876&version=stable&backtrace=0)有效。被删除的临时值不是数组,而是数组片。 – red75prime

+1

@ red75prime:我的理解是*那*行为是一种特殊情况,即立即借用的临时对象被提升,因为这种模式比较常见,否则会更加痛苦。 –

+0

另一种选择是使用“静态”,它存在于内存中,因此可以正常借用。 – zstewart

0

DK.'s answer是正确的,但我建议进行一个简单的更改以使您的代码正常工作 - 使用static而不是const

documentation about static and const

More specifically, constants in Rust have no fixed address in memory.

static items aren’t inlined upon use. This means that there is only one instance for each value, and it’s at a fixed location in memory.

切换到static可以让你得到你迭代的事情内存地址。

static VALUES: [(char, &str); 2] = [('A', "abc"), ('B', "acb")]; 

fn main() { 
    let result = VALUES.iter().find(|&&(name, _)| name == 'A'); 
} 

这里,resultOption<&(char, &str)>