I created an issue regarding this specific error message: https://github.com/rust-lang/rust/issues/16948
Wenderen was having some troubles with cloning &str the other day.
https://gist.github.com/wenderen/2efdea371b2ac7add6ae
Here, a Vec<&str>
is being cloned. Usually a clone solves all lifetime issues, but &str
isnāt Deref
, so the pointer (instead of the data) seems to be cloned, giving rise to a lifetime error.
This isnāt exactly a problem with the lifetime system, but it would be nice to have a cleaner set of error messages for &str
. Mostly one should be using String there, but thatās not entirely clear (perhaps clearer instructions on when to use String
and &str
in the docs might help?). &str
looks too much like &T
, but it doesnāt behave the same.
Just to add to this post, the error is on line 13 in the gist, where we do inputs.push(split_input.clone());
.
Sorry if someone has already given this example, Iām not event sure if it is a valid example but it seems like it should be allowed somehow and I canāt figure it out:
trait SomeTrait {
fn say_hello(&self);
}
struct SomeStruct;
impl SomeTrait for SomeStruct {
fn say_hello(&self) {
println!("EH")
}
}
struct AnotherStruct {
some_trait: Box<SomeTrait>
}
Results in:
rust.workspace/learn/src/main.rs:14:21: 14:30 error: explicit lifetime bound required rust.workspace/learn/src/main.rs:14 some_trait: Box
Somone just posted this gem on irc:
use std::collections::HashSet;
fn grab_words(
keys: &Vec<char>
) -> Vec<String>{
let mut keys_string = String::new();
for c in keys.iter(){
keys_string.push_char(*c);
}
keys_string.as_slice().split(' ').
map(|x| String::from_str(x)).
collect::<Vec<String>>()
}
fn evaluate_words(
keys: &Vec<char>,
word_list: &HashSet<&str>,
) -> f64 {
let words = grab_words(keys);
words.iter().fold(0.0f64, |err, w|{
if word_list.contains(&w.as_slice()){
err
} else {
err - 3.
}
}) / words.len() as f64
}
fn main(){
}
<anon>:23:5: 23:10 error: `words` does not live long enough
<anon>:23 words.iter().fold(0.0f64, |err, w|{
^~~~~
<anon>:20:14: 30:2 note: reference must be valid for the anonymous lifetime #3 defined on the block at 20:13...
<anon>:20 ) -> f64 {
<anon>:21 let words = grab_words(keys);
<anon>:22
<anon>:23 words.iter().fold(0.0f64, |err, w|{
<anon>:24 if word_list.contains(&w.as_slice()){
<anon>:25 err
...
<anon>:20:14: 30:2 note: ...but borrowed value is only valid for the block at 20:13
<anon>:20 ) -> f64 {
<anon>:21 let words = grab_words(keys);
<anon>:22
<anon>:23 words.iter().fold(0.0f64, |err, w|{
<anon>:24 if word_list.contains(&w.as_slice()){
<anon>:25 err
...
error: aborting due to previous error
I got this one:
pub fn get_configuration(url: String) -> Box {
src/olib/config/mod.rs:13:46: 13:60 error: explicit lifetime bound required
src/olib/config/mod.rs:13 pub fn get_configuration(url: String) -> Box<OConfiguration> {
^~~~~~~~~~~~~~
Anyone know what is wrong? Iād like to return a trait object that implements the trait OConfigurationā¦
Edit:
Changing to
pub fn get_configuration(url: String) -> Box<OConfiguration+'static> {
fixed itā¦
On Thu, Sep 18, 2014 at 11:50:06PM +0000, Gankro wrote:
This example is quite confusing to me for two reasons.
Letās first look at the error,
reference must be valid for the lifetime 'a as defined on the block at 26:67 but borrowed value is only valid for the block at 26:67
At first glance it appears that the compiler is saying āyou gave me x but I wanted xā where x is āthe block at 26:67ā. On second glance one might notice that the compiler is trying to tell you the reason why it wants the reference to be valid for lifetime 'a
(is this interpretation correct?). The wording of the error may or may not be clear to the acclimated reader, but either way the distinction between the use of x in what the compiler expected and what I provided is a bit subtle.
Now letās consider the issue itself. The code in question is attempting to return a reference a long-lived data structure (&SuffixTree<E>
) through an acess to a local structure defined in fn find_matches
(namely cursors
). If I change &**cur
to simply &dict
(which also has lifetime 'a
) then the code compiles, so clearly 'a
is not the issue.
At this point I was quite stumped. Thanks for shep
on #rust
we eventually determined that deref()
was the issue. While itās not clear from the impl
the lifetime the reference returned by deref
is that of the object being derefād. This however means that in using deref
the lifetime of the SuffixTree
reference was artificially shortened to the lifetime of the Cursor
that I got the reference through.
In hindsight this all seems reasonable enough; this is probably an abuse of Deref
anyways (it would be nice to hear confirmation of this). Ultimately I ended up adding a fn get(&self) -> &'a SuffixTree<E>
to Cursor<'a, E>
. Iām not sure what the compiler could do to better assist me in tracking down this issue.
Thanks!
What happened to this reply? Is it really as empty as it appears?
Itās a bug in the reply-via-email feature of Discourse. They require that you have your full comment at the top. If you try to inline your response, it just eats everything.
This one has me stumped today. First, the āconsider using an explicit lifetime as shownā is what I already am doing. Second, the āexpectedā and āfoundā types are showing as identical.
src/db/query.rs:35:9: 38:6 note: consider using an explicit lifetime parameter as shown: fn add_selection<'a>(&mut self, sql: Sql<'a>)
src/db/query.rs:35 pub fn add_selection<'a>(&mut self, sql: Sql<'a>)
src/db/query.rs:36 {
src/db/query.rs:37 self.selections.push(sql);
src/db/query.rs:38 }
src/db/query.rs:37:30: 37:33 error: mismatched types: expected `db::query::Sql<'a>`, found `db::query::Sql<'a>` (lifetime mismatch)
src/db/query.rs:37 self.selections.push(sql);
^~~
src/db/query.rs:37:30: 37:33 error: mismatched types: expected `db::query::Sql<'a>`, found `db::query::Sql<'a>` (lifetime mismatch)
src/db/query.rs:37 self.selections.push(sql);
Thanks, this is another helpful suggestion. Iād need to see more context, but almost certainly what is happening is that 'a is already in scope at the impl or type level.
I encountered the same problem as @mikedilger above, hereās the example in context: https://gist.github.com/maxsnew/9d3d30b469e7e39909d0
The bad error message is actually non-deterministic though! Compiling the buggy version with rustc --crate-type lib
sometimes gives the good error message and sometimes the bad one. The only issue I could find like this is marked fixed: https://github.com/rust-lang/rust/issues/13057
https://github.com/PistonDevelopers/event/issues/202
I tried adding 'a
in intuitive places to no avail =(. Any ideas?
Edit: Turns out mindlessly adding lifetimes wasnāt the solution - bvssvni switched Any
to Ptr
in intelligent places (because Any
requires static lifetimes) and fixed the issue!
Thanks for having this thread!
Whoops, I accidentally put the same error message twice. Fixed to show the two different error messages I get (non-deterministically).
Also Iām only getting the non-deterministic behavior on linux, on my mac Iām always getting the bad error message.
It wasnāt clear to me how to make a Box field for a trait type. For example:
trait A {
fn f(&self);
}
struct S {
a : Box<A>
}
a.rs:6:13: 6:14 error: explicit lifetime bound required
a.rs:6 a : Box<A>
I took me a while to figure out that what 'static has to do with my type.
Real life code is here https://github.com/Djuffin/rusty-chess/blob/master/search.rs
If struct doesnāt accept lifetime as a parameter, then 'static is pretty much the only option, you could mention it in the error message.
struct MyMapWrapper<'mw>(pub HashMap<&'mw str, &'mw str>);
impl<'mw, S: Decoder<E>, E> Decodable<S, E> for MyMapWrapper<'mw> {
fn decode(decoder: &mut S) -> Result<MyMapWrapper<'mw>, E> {
decoder.read_map(|decoder, len| {
let mut data_map: HashMap<&'mw str, &'mw str> = HashMap::new();
for i in range(0u, len) {
data_map.insert(match decoder.read_map_elt_key(i, |decoder| { decoder.read_str() }) {
Ok(key) => key.as_slice(), Err(err) => return Err(err)
},
match decoder.read_map_elt_val(i, |decoder| { decoder.read_str() }) {
Ok(val) => val.as_slice(), Err(err) => return Err(err)
});
}
Ok(MyMapWrapper(data_map))
})
}
}
Reports:
<anon>:17:48: 17:51 error: `key` does not live long enough
<anon>:17 Ok(key) => key.as_slice(), Err(err) => return Err(err)
^~~
<anon>:12:64: 25:6 note: reference must be valid for the lifetime 'mw as defined on the block at 12:63...
<anon>:12 fn decode(decoder: &mut S) -> Result<MyMapWrapper<'mw>, E> {
...
<anon>:16:33: 18:34 note: ...but borrowed value is only valid for the match at 16:32
<anon>:16 data_map.insert(match decoder.read_map_elt_key(i, |decoder| { decoder.read_str() }) {
<anon>:17 Ok(key) => key.as_slice(), Err(err) => return Err(err)
<anon>:18 },
<anon>:20:48: 20:51 error: `val` does not live long enough
<anon>:20 Ok(val) => val.as_slice(), Err(err) => return Err(err)
^~~
<anon>:12:64: 25:6 note: reference must be valid for the lifetime 'mw as defined on the block at 12:63...
<anon>:12 fn decode(decoder: &mut S) -> Result<MyMapWrapper<'mw>, E> {
...
<anon>:19:33: 21:34 note: ...but borrowed value is only valid for the match at 19:32
<anon>:19 match decoder.read_map_elt_val(i, |decoder| { decoder.read_str() }) {
<anon>:20 Ok(val) => val.as_slice(), Err(err) => return Err(err)
<anon>:21 });
I think both these statements (reference must be valid for the lifetime 'mw as defined on the block atā¦ & but borrowed value is only valid for the match) should also suggest something more clear (like the idea with try to store it with let
var), because itās hard to suggest what is the best way to do here w/o the help of compiler. I read it like it suggests me to somehow change the lifetime of key
/ val
, while I canāt. At least I feel it so, and seems itās open to share feelings like that in this thread :).
I tried this:
type ClosureAlias<T, U> = |T| -> U;
And the error is this:
lib.rs:39:27: 39:35 error: explicit lifetime bound required lib.rs:39 type ClosureAlias<T, U> = |T| -> U; ^~~~~~~~
It would be very helpful to get a suggestion on what the syntax for the lifetime bound is.
Hereās a confusing one:
use std::collections::HashMap;
struct WordGraph<'a> {
g: HashMap<&'a str, Box<Vec<&'a str>>>,
}
impl <'a> WordGraph<'a> {
fn new() -> WordGraph<'a> { WordGraph{g: HashMap::new(),} }
fn insert_word<'a>(&self, s: &'a str) {
if (!self.g.contains_key(&s)) {
self.g.insert(s, box Vec::new());
}
}
}
fn main() {
let mut wg = WordGraph::new();
let words = vec!("one" , "two" , "one" , "three" , "two" , "four");
for w in words.iter() { wg.insert_word(*w); }
}
The compilerās āconsiderā¦ā suggestion is less then helpful. From this playpen:
<anon>:10:14: 10:37 error: cannot infer an appropriate lifetime due to conflicting requirements
<anon>:10 if (!self.g.contains_key(&s)) {
^~~~~~~~~~~~~~~~~~~~~~~
<anon>:11:25: 11:26 error: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements
<anon>:11 self.g.insert(s, box() Vec::new());
^
<anon>:9:5: 13:6 help: consider using an explicit lifetime parameter as shown: fn insert_word<'a>(&self, s: &'a str)
<anon>:9 fn insert_word<'a>(&self, s: &'a str) {
<anon>:10 if (!self.g.contains_key(&s)) {
<anon>:11 self.g.insert(s, box() Vec::new());
<anon>:12 }
<anon>:13 }
error: aborting due to 2 previous errors
As you can see, the suggested function signature is exactly what I haveā¦ I donāt have a solution yet. This is intended to be an adjacency-list representation of a graph where the nodes are slices into strings (or 'static &str
refs) that are owned elsewhere, and where the lifetime of the references can be proven to outlive the HashMap/WordGraph itself.
I suspect the compiler message is a bug, but that aside, how would I solve this issue?
I believe the problem there is the shadowing of the lifetime 'a
. The declaration on the method is creating a new independent lifetime separate from the 'a
of WordGraph
. Removing the <'a>
from insert_word
should fix it.
Shadowing of lifetimes and generics leads to confusing messages because two lifetimes/types have the same textual name but are different internally. In this case the compiler is presumably trying to suggest the other 'a
leaving the declared one unused, I guess it should be stripping that declaration, or rename the method-local lifetime.
(Thereās a few issues in this vein, but Iām on my phone so I canāt find them easily, and I donāt think there are any that cover suggestions + shadowing specifically.)