Reputation: 117
I am trying to do the following
// Just removes redundant white space while also splitting the string
// with a whitespace.
fn split_whitespace(string: &str) -> Vec<&str> {
let words: Vec<&str> = string
.split_whitespace()
.filter(|&word| word != "")
.collect();
words
}
pub fn get_websites_from_hosts(hosts_path: &Path) -> Result<Vec<Website>, std::io::Error> {
let hosts_string = read_to_string(hosts_path)?;
let result: Vec<Website> = hosts_string
.lines()
.filter(|&line| split_whitespace(&line.to_owned()).len() == 2)
.map(|line| {
let ip_domain = split_whitespace(&line.to_owned());
Website {
domain_name: ip_domain[1], // This won't work because it is refering hosts_string which is a local variable of the function
redirect_ip: ip_domain[0], // the same case with this one.
is_blocked: true,
hosts_path,
}
})
.collect();
Ok(result)
}
What I want to achieve is to successfully return the Website struct while probably not editing the struct declaration.
And here is the Website struct declaration
#[derive(Debug, Clone)]
pub struct Website<'a> {
pub domain_name: &'a str,
pub redirect_ip: &'a str,
pub is_blocked: bool,
pub hosts_path: &'a Path,
}
And here is the error
error[E0515]: cannot return value referencing temporary value
--> src/parser.rs:21:13
|
20 | let ip_domain = split_whitespace(&line.to_owned());
| --------------- temporary value created here
21 | / Website {
22 | | domain_name: ip_domain[1],
23 | | redirect_ip: ip_domain[0],
24 | | is_blocked: true,
25 | | hosts_path,
26 | | }
| |_____________^ returns a value referencing data owned by the current function
For more information about this error, try `rustc --explain E0515`.
error: could not compile `website-blocker` due to previous error
warning: build failed, waiting for other jobs to finish...
error: could not compile `website-blocker` due to previous error
I would love a deep explanation and general tips to use when encountering this and the like problems
Upvotes: 0
Views: 632
Reputation: 15012
The &str
references in your struct refer to segments of the string returned by read_to_string
. That string (hosts_string
) is dropped and deallocated at the end of fn get_websites_from_hosts
, so if you could return references to it, they would be dangling. Rust prevents you from doing that.
Instead, you'll need to either move the read_to_string
outside that function, and pass the string in as an &str
or change your struct to hold owned values like String
, IpAddr
, etc.
#[derive(Debug, Clone)]
pub struct Website<'a> {
pub domain_name: String,
pub redirect_ip: IpAddr,
pub is_blocked: bool,
pub hosts_path: &'a Path,
}
If you want to avoid some String
allocations, you could use a "small-string optimization" library like compact_str
#[derive(Debug, Clone)]
pub struct Website<'a> {
// Stores a domain name of up to 24 bytes in place,
// without an extra heap allocation
pub domain_name: CompactString,
pub redirect_ip: IpAddr,
pub is_blocked: bool,
pub hosts_path: &'a Path,
}
Upvotes: 2