为什么这个变量定义意味着静态生命周期?
Why does this variable definition imply static lifetime?
我正在尝试对向量块执行函数,然后使用消息传递库将结果发回。
但是,我收到一个关于甚至不参与线程操作的向量生命周期的奇怪错误:
src/lib.rs:153:27: 154:25 error: borrowed value does not live long enough
src/lib.rs:153 let extended_segments = (segment_size..max_val)
error: src/lib.rs:154 .collect::<Vec<_>>()borrowed value does not live long enough
note: reference must be valid for the static lifetime...:153
let extended_segments = (segment_size..max_val)
src/lib.rs:153:3: 155:27: 154 .collect::<Vec<_>>()
note: but borrowed value is only valid for the statement at 153:2:
reference must be valid for the static lifetime...
src/lib.rs:
let extended_segments = (segment_size..max_val)
consider using a `let` binding to increase its lifetime
我尝试在迭代器周围移动并将生命周期添加到不同的地方,但我无法让检查器通过并且仍然停留在类型上。
下面是有问题的代码,基于 concurrency chapter in the Rust book. (Complete code is at github。)
use std::sync::mpsc;
use std::thread;
fn sieve_segment(a: &[usize], b: &[usize]) -> Vec<usize> {
vec![]
}
fn eratosthenes_sieve(val: usize) -> Vec<usize> {
vec![]
}
pub fn segmented_sieve_parallel(max_val: usize, mut segment_size: usize) -> Vec<usize> {
if max_val <= ((2 as i64).pow(16) as usize) {
// early return if the highest value is small enough (empirical)
return eratosthenes_sieve(max_val);
}
if segment_size > ((max_val as f64).sqrt() as usize) {
segment_size = (max_val as f64).sqrt() as usize;
println!("Segment size is larger than √{}. Reducing to {} to keep resource use down.",
max_val,
segment_size);
}
let small_primes = eratosthenes_sieve((max_val as f64).sqrt() as usize);
let mut big_primes = small_primes.clone();
let (tx, rx): (mpsc::Sender<Vec<usize>>, mpsc::Receiver<Vec<usize>>) = mpsc::channel();
let extended_segments = (segment_size..max_val)
.collect::<Vec<_>>()
.chunks(segment_size);
for this_segment in extended_segments.clone() {
let small_primes = small_primes.clone();
let tx = tx.clone();
thread::spawn(move || {
let sieved_segment = sieve_segment(&small_primes, this_segment);
tx.send(sieved_segment).unwrap();
});
}
for _ in 1..extended_segments.count() {
big_primes.extend(&rx.recv().unwrap());
}
big_primes
}
fn main() {}
如何理解和避免这个错误?我不确定如何使线程关闭的生命周期 and still have the function be reusable (i.e., not main()
). I'm not sure how to "consume all things that come into [the closure]" as mentioned in . And I'm not sure where to 以确保所有引用都成为移动,我也不确定我是否想要。
在尝试重现问题时,我鼓励您通过删除所有不相关的代码来创建 MCVE。在这种情况下,类似这样的事情似乎会产生相同的错误:
fn segmented_sieve_parallel(max_val: usize, segment_size: usize) {
let foo = (segment_size..max_val)
.collect::<Vec<_>>()
.chunks(segment_size);
}
fn main() {}
让我们分解一下:
- 在数字之间创建一个迭代器。
- 将它们全部收集到一个
Vec<usize>
。
- Return 包含对向量的引用的迭代器。
- 由于向量未绑定到任何变量,因此它在语句末尾被删除。这将使迭代器指向无效的内存区域,因此这是不允许的。
查看slice::chunks
的定义:
fn chunks(&self, size: usize) -> Chunks<T>
pub struct Chunks<'a, T> where T: 'a {
// some fields omitted
}
生命周期标记 'a
让您知道迭代器包含对某物的引用。 Lifetime elision 已经从函数中删除了 'a
,展开后看起来像这样:
fn chunks<'a>(&'a self, size: usize) -> Chunks<'a, T>
查看错误信息的这一行:
help: consider using a let
binding to increase its lifetime
您可以这样关注:
fn segmented_sieve_parallel(max_val: usize, segment_size: usize) {
let foo = (segment_size..max_val)
.collect::<Vec<_>>();
let bar = foo.chunks(segment_size);
}
fn main() {}
虽然我会写成
fn segmented_sieve_parallel(max_val: usize, segment_size: usize) {
let foo: Vec<_> = (segment_size..max_val).collect();
let bar = foo.chunks(segment_size);
}
fn main() {}
将此代码重新插入到您原来的问题中并不能解决问题,但会更容易理解。那是因为您正试图传递对 thread::spawn
的引用,它可能比当前线程还存在。因此,传递给 thread::spawn
的所有内容都必须具有 'static
生命周期。有大量问题详细说明了为什么必须避免这种情况以及一连串的解决方案,包括作用域线程和克隆向量。
克隆载体最简单,但效率可能很低:
for this_segment in extended_segments.clone() {
let this_segment = this_segment.to_vec();
// ...
}
我正在尝试对向量块执行函数,然后使用消息传递库将结果发回。
但是,我收到一个关于甚至不参与线程操作的向量生命周期的奇怪错误:
src/lib.rs:153:27: 154:25 error: borrowed value does not live long enough
src/lib.rs:153 let extended_segments = (segment_size..max_val)
error: src/lib.rs:154 .collect::<Vec<_>>()borrowed value does not live long enough
note: reference must be valid for the static lifetime...:153
let extended_segments = (segment_size..max_val)
src/lib.rs:153:3: 155:27: 154 .collect::<Vec<_>>()
note: but borrowed value is only valid for the statement at 153:2:
reference must be valid for the static lifetime...
src/lib.rs:
let extended_segments = (segment_size..max_val)
consider using a `let` binding to increase its lifetime
我尝试在迭代器周围移动并将生命周期添加到不同的地方,但我无法让检查器通过并且仍然停留在类型上。
下面是有问题的代码,基于 concurrency chapter in the Rust book. (Complete code is at github。)
use std::sync::mpsc;
use std::thread;
fn sieve_segment(a: &[usize], b: &[usize]) -> Vec<usize> {
vec![]
}
fn eratosthenes_sieve(val: usize) -> Vec<usize> {
vec![]
}
pub fn segmented_sieve_parallel(max_val: usize, mut segment_size: usize) -> Vec<usize> {
if max_val <= ((2 as i64).pow(16) as usize) {
// early return if the highest value is small enough (empirical)
return eratosthenes_sieve(max_val);
}
if segment_size > ((max_val as f64).sqrt() as usize) {
segment_size = (max_val as f64).sqrt() as usize;
println!("Segment size is larger than √{}. Reducing to {} to keep resource use down.",
max_val,
segment_size);
}
let small_primes = eratosthenes_sieve((max_val as f64).sqrt() as usize);
let mut big_primes = small_primes.clone();
let (tx, rx): (mpsc::Sender<Vec<usize>>, mpsc::Receiver<Vec<usize>>) = mpsc::channel();
let extended_segments = (segment_size..max_val)
.collect::<Vec<_>>()
.chunks(segment_size);
for this_segment in extended_segments.clone() {
let small_primes = small_primes.clone();
let tx = tx.clone();
thread::spawn(move || {
let sieved_segment = sieve_segment(&small_primes, this_segment);
tx.send(sieved_segment).unwrap();
});
}
for _ in 1..extended_segments.count() {
big_primes.extend(&rx.recv().unwrap());
}
big_primes
}
fn main() {}
如何理解和避免这个错误?我不确定如何使线程关闭的生命周期 main()
). I'm not sure how to "consume all things that come into [the closure]" as mentioned in
在尝试重现问题时,我鼓励您通过删除所有不相关的代码来创建 MCVE。在这种情况下,类似这样的事情似乎会产生相同的错误:
fn segmented_sieve_parallel(max_val: usize, segment_size: usize) {
let foo = (segment_size..max_val)
.collect::<Vec<_>>()
.chunks(segment_size);
}
fn main() {}
让我们分解一下:
- 在数字之间创建一个迭代器。
- 将它们全部收集到一个
Vec<usize>
。 - Return 包含对向量的引用的迭代器。
- 由于向量未绑定到任何变量,因此它在语句末尾被删除。这将使迭代器指向无效的内存区域,因此这是不允许的。
查看slice::chunks
的定义:
fn chunks(&self, size: usize) -> Chunks<T>
pub struct Chunks<'a, T> where T: 'a {
// some fields omitted
}
生命周期标记 'a
让您知道迭代器包含对某物的引用。 Lifetime elision 已经从函数中删除了 'a
,展开后看起来像这样:
fn chunks<'a>(&'a self, size: usize) -> Chunks<'a, T>
查看错误信息的这一行:
help: consider using a
let
binding to increase its lifetime
您可以这样关注:
fn segmented_sieve_parallel(max_val: usize, segment_size: usize) {
let foo = (segment_size..max_val)
.collect::<Vec<_>>();
let bar = foo.chunks(segment_size);
}
fn main() {}
虽然我会写成
fn segmented_sieve_parallel(max_val: usize, segment_size: usize) {
let foo: Vec<_> = (segment_size..max_val).collect();
let bar = foo.chunks(segment_size);
}
fn main() {}
将此代码重新插入到您原来的问题中并不能解决问题,但会更容易理解。那是因为您正试图传递对 thread::spawn
的引用,它可能比当前线程还存在。因此,传递给 thread::spawn
的所有内容都必须具有 'static
生命周期。有大量问题详细说明了为什么必须避免这种情况以及一连串的解决方案,包括作用域线程和克隆向量。
克隆载体最简单,但效率可能很低:
for this_segment in extended_segments.clone() {
let this_segment = this_segment.to_vec();
// ...
}