I want to implement a Timer object, which is owned by Foo object and it should call the Foo object's method periodically. I just implemented adding callback function (which is executing Foo object's method) to the Timer as below, but it failed to compile due to conflicting lifetime requirements.
Code (does not containing executing callback function part)
use std::sync::Mutex;
#[derive(Default)]
struct Timer<'a> {
callbacks: Mutex<Vec<Box<dyn Fn() + 'a>>>,
}
impl<'a> Timer<'a> {
fn add(&self, callback: Box<dyn Fn() + 'a>) {
let mut callbacks = self.callbacks.lock().unwrap();
callbacks.push(callback);
}
}
#[derive(Default)]
struct Foo<'a> {
value: usize,
timer: Timer<'a>,
}
impl<'a> Foo<'a> {
fn callback(&self) {
println!("value is {}", self.value);
}
fn process(&self) {
let callback = || {
self.callback();
};
self.timer.add(Box::new(callback));
}
}
fn main() {
let foo = Foo::default();
foo.process();
}
failed to compile with below error
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:28:24
|
28 | let callback = || {
| ________________________^
29 | | self.callback();
30 | | };
| |_________^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 27:5...
--> src/main.rs:27:5
|
27 | fn process(&self) {
| ^^^^^^^^^^^^^^^^^
note: ...so that the types are compatible
--> src/main.rs:28:24
|
28 | let callback = || {
| ________________________^
29 | | self.callback();
30 | | };
| |_________^
= note: expected `(&&Foo<'a>,)`
found `(&&Foo<'a>,)`
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 22:6...
--> src/main.rs:22:6
|
22 | impl<'a> Foo<'a> {
| ^^
note: ...so that the types are compatible
--> src/main.rs:32:20
|
32 | self.timer.add(Box::new(callback));
| ^^^
= note: expected `&Timer<'_>`
found `&Timer<'a>`
error: aborting due to previous error
I think the error comes from the process method in Foo object takes self as &'_ lifetime, but self.timer need &'a lifetime.
When I added &'a lifetime to self in process and callback method as below,
...
impl<'a> Foo<'a> {
fn callback(&'a self) {
...
}
fn process(&'a self) {
...
}
}
...
Below error occured-
error[E0597]: `self` does not live long enough
--> src/main.rs:29:13
|
22 | impl<'a> Foo<'a> {
| -- lifetime `'a` defined here
...
28 | let callback = || {
| -- value captured here
29 | self.callback();
| ^^^^ borrowed value does not live long enough
...
32 | self.timer.add(Box::new(callback));
| ------------------ cast requires that `self` is borrowed for `'a`
33 | }
| - `self` dropped here while still borrowed
error[E0597]: `foo` does not live long enough
--> src/main.rs:39:5
|
39 | foo.process();
| ^^^ borrowed value does not live long enough
40 | }
| -
| |
| `foo` dropped here while still borrowed
| borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_>`
error: aborting due to 2 previous errors
How to solve this problem?
The problem here is that you want to create a reference back to Foo inside Timer, but if Foo gets moved or if the Timer gets moved out of Foo while Foo is destroyed, this reference would be invalid. One (naive) way to fix this would be to use a reference counter for value and avoid referencing Foo directly:
#[derive(Default)]
struct Foo<'a> {
value: Rc<usize>,
timer: Timer<'a>,
}
impl<'a> Foo<'a> {
fn process(&self) {
let value_rc = self.value.clone();
let callback = move || {
println!("value is {}", *value_rc);
};
self.timer.add(Box::new(callback));
}
}
This makes using value a bit more difficult and would have a runtime overhead in Rc (or Arc if multithreaded). A better solution would probably be to split the structs entirely and use the normal lifetime rules like this:
#[derive(Default)]
struct Foo {
value: usize,
}
impl Foo {
fn callback(&self) {
println!("value is {}", self.value);
}
}
fn main() {
let foo = Foo::default();
let timer = Timer::default();
let callback = || {
foo.callback();
};
timer.add(Box::new(callback));
}
This way, Rust will make sure that foo, timer and callback each live long enough, because of the order that they are created and destroyed in inside main().
Related
Let's suppose I have code like this:
struct Struct0 {
s1: Struct1,
v: Vec<Box<dyn Tr>>
}
impl Struct0 {
fn a(&mut self) {
self.v = self.s1.func();
}
}
struct Struct1 {}
impl<'a> Struct1 {
fn func(&'a self) -> Vec<Box<dyn Tr + 'a>> {
vec![Box::new(Struct2 { some_reference: &self } )]
}
}
trait Tr {
//...
}
struct Struct2<'a> {
some_reference: &'a Struct1
}
impl Tr for Struct2<'_> {
//...
}
fn main() {
}
This gives the following error:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/main.rs:8:26
|
8 | self.v = self.s1.func();
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 7:5...
--> src/main.rs:7:5
|
7 | / fn a(&mut self) {
8 | | self.v = self.s1.func();
9 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:8:18
|
8 | self.v = self.s1.func();
| ^^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the expression is assignable
--> src/main.rs:8:18
|
8 | self.v = self.s1.func();
| ^^^^^^^^^^^^^^
= note: expected `std::vec::Vec<std::boxed::Box<(dyn Tr + 'static)>>`
found `std::vec::Vec<std::boxed::Box<dyn Tr>>`
I would like to tell the Rust compiler that that the lifetime of the returned value should be the lifetime of the Struct1. That vector (with its values) should live as long as the struct from which that method is called. How can I say that?
I have a function that accepts a reference to an enum, which I need to parse by matching the enum and reading its content. One of the variants of the enum (not in the simplified minimal working example below), may contain as value the type of the enum itself, therefore I may need to recursively call the same function to parse its value.
I would like to write a function that acts as a filter and returns an Option::Some containing a reference to the content of the enum variant, or None if the value must be discarded.
What follows is a minimal working (not-really compiling) example:
enum Data<'a> {
Value(&'a String),
Null,
}
fn main() {
let s = String::new();
let d = Data::Value(&s);
let equal = |d: &Data| -> Option<&String> {
if let Data::Value(s) = d {
Some(s)
} else {
None
}
};
parse(&d, equal);
//parse(&d, equal_filter);
}
fn equal_filter<'a>(d: &'a Data) -> Option<&'a String> {
if let Data::Value(s) = d {
Some(s)
} else {
None
}
}
fn parse<'a, F>(data: &Data<'a>, filter: F)
where
F: Fn(&Data<'a>) -> Option<&'a String>,
{
filter(data);
}
Playground.
I tried to compile the code by using a closure first, but in that case I get the error:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:11:33
|
11 | if let Data::Value(s) = d {
| ^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 10:17...
--> src/main.rs:10:17
|
10 | let equal = |d: &Data| -> Option<&String> {
| _________________^
11 | | if let Data::Value(s) = d {
12 | | Some(s)
13 | | } else {
14 | | None
15 | | }
16 | | };
| |_____^
= note: ...so that the types are compatible:
expected &Data<'_>
found &Data<'_>
note: but, the lifetime must be valid for the expression at 18:5...
--> src/main.rs:18:5
|
18 | parse(&d, equal);
| ^^^^^
note: ...so that a type/lifetime parameter is in scope here
--> src/main.rs:18:5
|
18 | parse(&d, equal);
| ^^^^^
So I tried with a function, but a got another error:
error[E0271]: type mismatch resolving `for<'r> <for<'a, 's> fn(&'a Data<'s>) -> std::option::Option<&'a std::string::String> {equal_filter} as std::ops::FnOnce<(&'r Data<'_>,)>>::Output == std::option::Option<&std::string::String>`
--> src/main.rs:19:5
|
19 | parse(&d, equal_filter);
| ^^^^^ expected bound lifetime parameter, found concrete lifetime
|
note: required by `parse`
--> src/main.rs:30:1
|
30 | / fn parse<'a, F>(data: &Data<'a>, filter: F)
31 | | where
32 | | F: Fn(&Data<'a>) -> Option<&'a String>,
33 | | {
34 | | filter(data);
35 | | }
| |_^
I would prefer to solve the issue using the closure, but I don't know how to proceed even by using the function.
Ultimately, this is caused due to limitations in Rust's type inference. Specifically, if a closure is passed immediately to a function that uses it, the compiler can infer what the argument and return types are. Unfortunately, when it is stored in a variable before being used, the compiler does not perform the same level of inference.
Inline your closure and it works:
enum Data<'a> {
Value(&'a String),
Null,
}
fn main() {
let s = String::new();
let d = Data::Value(&s);
parse(&d, |d| match d {
Data::Value(s) => Some(s),
_ => None,
});
}
fn parse<'a, F>(data: &Data<'a>, filter: F)
where
F: Fn(&Data<'a>) -> Option<&'a String>,
{
filter(data);
}
However, I'd encourage you to instead create methods on the enum and participate in the idiomatic set of conversion functions:
enum Data<'a> {
Value(&'a String),
Null,
}
impl<'a> Data<'a> {
fn as_value(&self) -> Option<&'a str> {
match self {
Data::Value(s) => Some(s),
_ => None,
}
}
}
fn main() {
let s = String::new();
let d = Data::Value(&s);
parse(&d, Data::as_value);
}
fn parse<'a, F>(data: &Data<'a>, filter: F)
where
F: Fn(&Data<'a>) -> Option<&'a str>,
{
filter(data);
}
Your function variant doesn't work because you've put the relevant lifetime in the wrong place:
// Wrong
fn equal_filter<'a>(d: &'a Data) -> Option<&'a String>
// Right
fn equal_filter<'a>(d: &Data<'a>) -> Option<&'a String>
Using either #[deny(elided_lifetimes_in_paths)] or #[deny(rust_2018_idioms)] will guide you to this:
error: hidden lifetime parameters in types are deprecated
--> src/main.rs:12:22
|
12 | let equal = |d: &Data| -> Option<&String> {
| ^^^^- help: indicate the anonymous lifetime: `<'_>`
|
error: hidden lifetime parameters in types are deprecated
--> src/main.rs:24:28
|
24 | fn equal_filter<'a>(d: &'a Data) -> Option<&'a String> {
| ^^^^- help: indicate the anonymous lifetime: `<'_>`
See also:
How to declare a lifetime for a closure argument?
In Rust 1.29.0 one of my tests has started failing. I managed to get the strange bug down to this example:
#[derive(Clone, Debug)]
struct CountDrop<'a>(&'a std::cell::RefCell<usize>);
struct MayContainValue<T> {
value: std::mem::ManuallyDrop<T>,
has_value: u32,
}
impl<T: Clone> Clone for MayContainValue<T> {
fn clone(&self) -> Self {
Self {
value: if self.has_value > 0 {
self.value.clone()
} else {
unsafe { std::mem::uninitialized() }
},
has_value: self.has_value,
}
}
}
impl<T> Drop for MayContainValue<T> {
fn drop(&mut self) {
if self.has_value > 0 {
unsafe {
std::mem::ManuallyDrop::drop(&mut self.value);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn check_drops() {
let n = 2000;
let drops = std::cell::RefCell::new(0usize);
let mut slots = Vec::new();
for _ in 0..n {
slots.push(MayContainValue {
value: std::mem::ManuallyDrop::new(CountDrop(&drops)),
has_value: 1,
});
}
unsafe { std::mem::ManuallyDrop::drop(&mut slots[0].value); }
slots[0].has_value = 0;
assert_eq!(slots.len(), slots.clone().len());
}
}
I know the code looks strange; it is all ripped out of context. I reproduced this problem with cargo test on 64-bit Ubuntu on Rust 1.29.0. A friend could not reproduce on Windows with the same Rust version.
Other things that stop reproduction:
Lowering n below ~900.
Not running the example from within cargo test.
Replacing CountDrop's member with u64.
Using a Rust version before 1.29.0.
What's going on here? Yes, MayContainValue can have an uninitialized member, but this is never used in any way.
I also managed to reproduce this on play.rust-lang.org.
I'm not interested in 'solutions' that involve re-engineering MayContainValue in some safe way with Option or enum, I'm using manual storage and occupied/vacant discrimination for a good reason.
TL;DR: Yes, creating an uninitialized reference is always undefined behavior. You cannot use mem::uninitialized safely with generics. There is not currently a good workaround for your specific case.
Running your code in valgrind reports 3 errors, each with the same stack trace:
==741== Conditional jump or move depends on uninitialised value(s)
==741== at 0x11907F: <alloc::vec::Vec<T> as alloc::vec::SpecExtend<T, I>>::spec_extend (vec.rs:1892)
==741== by 0x11861C: <alloc::vec::Vec<T> as alloc::vec::SpecExtend<&'a T, I>>::spec_extend (vec.rs:1942)
==741== by 0x11895C: <alloc::vec::Vec<T>>::extend_from_slice (vec.rs:1396)
==741== by 0x11C1A2: alloc::slice::hack::to_vec (slice.rs:168)
==741== by 0x11C643: alloc::slice::<impl [T]>::to_vec (slice.rs:369)
==741== by 0x118C1E: <alloc::vec::Vec<T> as core::clone::Clone>::clone (vec.rs:1676)
==741== by 0x11AF89: md::tests::check_drops (main.rs:51)
==741== by 0x119D39: md::__test::TESTS::{{closure}} (main.rs:36)
==741== by 0x11935D: core::ops::function::FnOnce::call_once (function.rs:223)
==741== by 0x11F09E: {{closure}} (lib.rs:1451)
==741== by 0x11F09E: call_once<closure,()> (function.rs:223)
==741== by 0x11F09E: <F as alloc::boxed::FnBox<A>>::call_box (boxed.rs:642)
==741== by 0x17B469: __rust_maybe_catch_panic (lib.rs:105)
==741== by 0x14044F: try<(),std::panic::AssertUnwindSafe<alloc::boxed::Box<FnBox<()>>>> (panicking.rs:289)
==741== by 0x14044F: catch_unwind<std::panic::AssertUnwindSafe<alloc::boxed::Box<FnBox<()>>>,()> (panic.rs:392)
==741== by 0x14044F: {{closure}} (lib.rs:1406)
==741== by 0x14044F: std::sys_common::backtrace::__rust_begin_short_backtrace (backtrace.rs:136)
Reducing while keeping the Valgrind error (or one extremely similar) leads to
use std::{iter, mem};
fn main() {
let a = unsafe { mem::uninitialized::<&()>() };
let mut b = iter::once(a);
let c = b.next();
let _d = match c {
Some(_) => 1,
None => 2,
};
}
Running this smaller reproduction in Miri in the playground leads to this error:
error[E0080]: constant evaluation error: attempted to read undefined bytes
--> src/main.rs:7:20
|
7 | let _d = match c {
| ^ attempted to read undefined bytes
|
note: inside call to `main`
--> /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:74:34
|
74| lang_start_internal(&move || main().report(), argc, argv)
| ^^^^^^
note: inside call to `closure`
--> /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:59:75
|
59| ::sys_common::backtrace::__rust_begin_short_backtrace(move || main())
| ^^^^^^
note: inside call to `closure`
--> /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/sys_common/backtrace.rs:136:5
|
13| f()
| ^^^
note: inside call to `std::sys_common::backtrace::__rust_begin_short_backtrace::<[closure#DefId(1/1:1823 ~ std[82ff]::rt[0]::lang_start_internal[0]::{{closure}}[0]::{{closure}}[0]) 0:&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>`
--> /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:59:13
|
59| ::sys_common::backtrace::__rust_begin_short_backtrace(move || main())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside call to `closure`
--> /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/panicking.rs:310:40
|
31| ptr::write(&mut (*data).r, f());
| ^^^
note: inside call to `std::panicking::try::do_call::<[closure#DefId(1/1:1822 ~ std[82ff]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>`
--> /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/panicking.rs:306:5
|
30| / fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
30| | unsafe {
30| | let data = data as *mut Data<F, R>;
30| | let f = ptr::read(&mut (*data).f);
31| | ptr::write(&mut (*data).r, f());
31| | }
31| | }
| |_____^
note: inside call to `std::panicking::try::<i32, [closure#DefId(1/1:1822 ~ std[82ff]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe]>`
--> /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/panic.rs:392:9
|
39| panicking::try(f)
| ^^^^^^^^^^^^^^^^^
note: inside call to `std::panic::catch_unwind::<[closure#DefId(1/1:1822 ~ std[82ff]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>`
--> /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:58:25
|
58| let exit_code = panic::catch_unwind(|| {
| _________________________^
59| | ::sys_common::backtrace::__rust_begin_short_backtrace(move || main())
60| | });
| |__________^
note: inside call to `std::rt::lang_start_internal`
--> /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:74:5
|
74| lang_start_internal(&move || main().report(), argc, argv)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The short version is that mem::uninitialized creates a null pointer, which is being treated as a reference. That's the undefined behavior.
In your original code, the Vec::clone is implemented by iterating over an iterator. Iterator::next returns an Option<T>, so you have an option of a reference, which causes the null pointer optimization to kick in. This counts as a None, which terminates the iteration early, resulting in your empty second vector.
It turns out that having mem::uninitialized, a piece of code that gives you C-like semantics, is a giant footgun and is frequently misused (surprise!), so you aren't alone here. The main things you should follow as replacements are:
Tracking issue for RFC 1892, "Deprecate uninitialized in favor of a new MaybeUninit type"
Implement MaybeUninit
Rust 1.29.0 changed the definition of ManuallyDrop. It used to be a union (with a single member), but now it's a struct and a lang item. The role of the lang item in the compiler is to force the type to not have a destructor, even if it wraps a type that has once.
I tried copying the old definition of ManuallyDrop (which requires nightly, unless a T: Copy bound is added) and using that instead of the one from std, and it avoids the issue (at least on the Playground). I also tried dropping the second slot (slots[1]) instead of the first (slots[0]) and that also happens to work.
Although I haven't been able to reproduce the problem natively on my system (running Arch Linux x86_64), I found something interesting by using miri:
francis#francis-arch /data/git/miri master
$ MIRI_SYSROOT=~/.xargo/HOST cargo run -- /data/src/rust/so-manually-drop-1_29/src/main.rs
Finished dev [unoptimized + debuginfo] target(s) in 0.03s
Running `target/debug/miri /data/src/rust/so-manually-drop-1_29/src/main.rs`
error[E0080]: constant evaluation error: attempted to read undefined bytes
--> /home/francis/.rustup/toolchains/nightly-2018-09-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/liballoc/vec.rs:1903:32
|
1903 | for element in iterator {
| ^^^^^^^^ attempted to read undefined bytes
|
note: inside call to `<std::vec::Vec<T> as std::vec::SpecExtend<T, I>><MayContainValue<CountDrop>, std::iter::Cloned<std::slice::Iter<MayContainValue<CountDrop>>>>::spec_extend`
--> /home/francis/.rustup/toolchains/nightly-2018-09-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/liballoc/vec.rs:1953:9
|
1953 | self.spec_extend(iterator.cloned())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside call to `<std::vec::Vec<T> as std::vec::SpecExtend<&'a T, I>><MayContainValue<CountDrop>, std::slice::Iter<MayContainValue<CountDrop>>>::spec_extend`
--> /home/francis/.rustup/toolchains/nightly-2018-09-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/liballoc/vec.rs:1402:9
|
1402 | self.spec_extend(other.iter())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside call to `<std::vec::Vec<T>><MayContainValue<CountDrop>>::extend_from_slice`
--> /home/francis/.rustup/toolchains/nightly-2018-09-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/liballoc/slice.rs:168:9
|
168 | vector.extend_from_slice(s);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside call to `std::slice::hack::to_vec::<MayContainValue<CountDrop>>`
--> /home/francis/.rustup/toolchains/nightly-2018-09-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/liballoc/slice.rs:369:9
|
369 | hack::to_vec(self)
| ^^^^^^^^^^^^^^^^^^
note: inside call to `std::slice::<impl [T]><MayContainValue<CountDrop>>::to_vec`
--> /home/francis/.rustup/toolchains/nightly-2018-09-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/liballoc/vec.rs:1687:9
|
1687 | <[T]>::to_vec(&**self)
| ^^^^^^^^^^^^^^^^^^^^^^
note: inside call to `<std::vec::Vec<T> as std::clone::Clone><MayContainValue<CountDrop>>::clone`
--> /data/src/rust/so-manually-drop-1_29/src/main.rs:54:33
|
54 | assert_eq!(slots.len(), slots.clone().len());
| ^^^^^^^^^^^^^
note: inside call to `tests::check_drops`
--> /data/src/rust/so-manually-drop-1_29/src/main.rs:33:5
|
33 | tests::check_drops();
| ^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0080`.
(Note: I can get the same error without using Xargo, but then miri doesn't show the source code for the stack frames in std.)
If I do this again with the original definition of ManuallyDrop, then miri doesn't report any issue. This confirms that the new definition of ManuallyDrop causes your program to have undefined behavior.
When I change std::mem::uninitialized() to std::mem::zeroed(), I can reliably reproduce the issue. When running natively, if it happens that the uninitialized memory is all zeroes, then you'll get the issue, otherwise you won't.
By calling std::mem::zeroed(), I've made the program generate null references, which are documented as undefined behavior in Rust. When the vector is cloned, an iterator is used (as shown in miri's output above). Iterator::next returns an Option<T>; that T here has a reference in it (coming from CountDrops), which causes Option's memory layout to be optimized: instead of having a discrete discriminant, it uses a null reference to represent its None value. Since I am generating null references, the iterator returns None on the first item and thus the vector ends up empty.
What's interesting is that when ManuallyDrop was defined as a union, Option's memory layout was not optimized.
println!("{}", std::mem::size_of::<Option<std::mem::ManuallyDrop<CountDrop<'static>>>>());
// prints 16 in Rust 1.28, but 8 in Rust 1.29
There is a discussion about this situation in #52898.
Simple code as below:
fn main() {
let R1 = TestResult(10, 20);
match R1 {
Ok(value) => println!("{}", value),
Err(error) => println!("{}", error),
}
}
fn TestResult(a1: i32, a2: i32) -> Result<i32, String> {
if a1 > a2 {
//Compile Pass
//Ok(100)
//Compile with error why ?
std::result::Result<i32, std::string::String>::Ok(100)
} else {
Err(String::from("Error Happens!"))
}
}
I get the error
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `,`
--> src/main.rs:15:32
|
15 | std::result::Result<i32, std::string::String>::Ok(100)
| ^ expected one of 8 possible tokens here
error[E0423]: expected value, found enum `std::result::Result`
--> src/main.rs:15:9
|
15 | std::result::Result<i32, std::string::String>::Ok(100)
| ^^^^^^^^^^^^^^^^^^^
|
= note: did you mean to use one of the following variants?
- `std::result::Result::Err`
- `std::result::Result::Ok`
error[E0423]: expected value, found builtin type `i32`
--> src/main.rs:15:29
|
15 | std::result::Result<i32, std::string::String>::Ok(100)
| ^^^ not a value
error[E0308]: mismatched types
--> src/main.rs:15:9
|
9 | fn TestResult(a1: i32, a2: i32) -> Result<i32, String> {
| ------------------- expected `std::result::Result<i32, std::string::String>` because of return type
...
15 | std::result::Result<i32, std::string::String>::Ok(100)
| ^^^^^^^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found bool
|
= note: expected type `std::result::Result<i32, std::string::String>`
found type `bool`
I'm using Rust 1.26.0.
Because that's a syntax error. The correct syntax uses the turbofish (::<>) on the enum variant:
std::result::Result::Ok::<i32, std::string::String>(100)
You also shouldn't use an explicit type unless you really need it — it's not idiomatic. Rust variables and functions use snake_case.
fn main() {
let r1 = test_result(10, 20);
match r1 {
Ok(value) => println!("{}", value),
Err(error) => println!("{}", error),
}
}
fn test_result(a1: i32, a2: i32) -> Result<i32, String> {
if a1 > a2 {
Ok(100)
} else {
Err(String::from("Error Happens!"))
}
}
This question already has answers here:
"borrowed value does not live long enough" seems to blame the wrong thing
(2 answers)
Cannot obtain a mutable reference when iterating a recursive structure: cannot borrow as mutable more than once at a time
(4 answers)
Closed 5 years ago.
I am a newcomer to the huge world of Rust. I have been learning it for a week and got some concept going, however something is a bit wrong with my classic implementation of singly-linked list and it is connected with borrowing and my lack of understanding of lifetimes. Here is the code:
use std::fmt::Display;
#[derive(Debug)]
struct Node<T> {
payload: T,
next: Option<Box<Node<T>>>
}
impl<T> Node<T>
where T: Display + PartialEq {
fn new(payload: T, next: Option<Box<Node<T>>>) -> Option<Box<Node<T>>> {
Some(Box::new(Node {
payload,
next
}))
}
fn print_nodes(&mut self) {
let this = self;
loop {
match this.next {
Some(_) => {
print!("{} -> ", &this.payload);
}
None => {
print!("{}", &this.payload);
break;
}
}
this = &mut this.next.unwrap();
}
}
}
fn main() {
let a = Node::new(String::from("hello"), None);
let b = Node::new(String::from("hey"), a);
let mut d = b.unwrap();
d.print_nodes();
}
Here is the error I get:
error[E0597]: borrowed value does not live long enough
--> main.rs:31:43
|
31 | this = &mut this.next.unwrap();
| ------------------^ temporary value dropped here while still borrowed
| |
| temporary value created here
32 | }
33 | }
| - temporary value needs to live until here
|
= note: consider using a `let` binding to increase its lifetime
error[E0507]: cannot move out of borrowed content
--> main.rs:31:25
|
31 | this = &mut this.next.unwrap();
| ^^^^ cannot move out of borrowed content
error[E0384]: cannot assign twice to immutable variable `this`
--> main.rs:31:13
|
20 | let this = self;
| ---- first assignment to `this`
...
31 | this = &mut this.next.unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
I would be grateful if somebody could explain my mistake and recommend something to fix this.