Ownership problem with char to string conversion
Solution 1:
Your failing code is equivalent to this one:
for a in &ARRAY {
let temp = a.to_string();
list.push(Text::new(&temp));
drop(temp);
}
Except that the temporary variable has a name in my code (the call to drop()
is redundant, I added it for clarity).
So all the temporaries created during the loop are being added as references to the list, remember that Text
holds a reference, not the string itself. But these temporaries do not survive the iteration where they are created, so your list contains dangling references. Rust detects that and fails to compile.
The easy solution would be to modify Text
to hold the String
itself, instead of a reference. If you cannot modify that, then your strings have to live somewhere, you can build a Vec<String>
and get the references from there:
fn test() {
const ARRAY: [char; 3] = ['a', 'b', 'c'];
let mut tmps: Vec<String> = Vec::new();
for a in &ARRAY {
tmps.push(a.to_string());
}
let list: Vec<Text> = tmps
.iter()
.map(|s| Text::new(s))
.collect();
}
Your second code works simply because now you array contains static references &'static str
so there is no temporary variables anywhere.
Solution 2:
What's special is that to_string()
creates an owned string, whereas "..."
gives you a &'static str
. The owned string has a clear life cycle which ends at the end of its scope, when it deallocates the memory where the data is stored. You attempt to store references to such strings and hold on to them after the string has already been deallocated.
The Text
type from the external crate is designed to borrow data owned by someone else. If you can't change that, you'll simply need to make sure that you keep the owned values around for at least as long as the Text
values. For example:
fn test() {
let mut list: Vec<Text> = Vec::new();
const ARRAY: [char; 3] = ['a', 'b', 'c'];
// keep the strings live
let strings: Vec<String> = ARRAY.iter().map(|c| c.to_string()).collect();
// `Text`s in `list` refer to strings in `strings`
for s in &strings {
list.push(Text::new(s));
}
}