This question already has answers here:
How to convert a String into a &'static str
(4 answers)
Closed 7 years ago.
I'm trying to read input from the user, and then use it as the URL for the POP3 library. When converting the String that I get to a string slice, it doesn't live long enough to be used. This is strange to me for two reasons:
Because everything that uses the POP3 object is inside the same block, so the lifetime of the str slice should be that of the entire block, which would cover everything
I've tried almost every different code configuration I could think of, and to no avail, I get the same error every time.
extern crate pop3;
extern crate smtp;
extern crate openssl;
extern crate libc;
use openssl::ssl::{SslContext, SslMethod};
use pop3::POP3Stream;
use pop3::POP3Result::{POP3Stat, POP3List, POP3Message};
mod readline;
use readline::*;
fn main() {
let place = match readline("URL: ") { // Problem line
Some(input) => { // Problem line
let place: &'static str = &input[..]; // Problem line
let mut email_socket = match POP3Stream::connect(place, 995, Some(SslContext::new(SslMethod::Sslv23).unwrap())) { // Problem line
Ok(s) => s,
Err(e) => panic!("{}", e)
};
match readline("Username: ") {
Some(username) => {
match readline("Password: ") {
Some(password) => { email_socket.login(&*username, &*password); },
None => println!("Please enter a password.")
}
},
None => println!("Please enter a username.")
};
let stat = email_socket.stat();
match stat {
POP3Stat {num_email,
mailbox_size} => println!("num_email: {}, mailbox_size:{}", num_email, mailbox_size),
e => println!("There was an error signing into your server."),
}
let list_all = email_socket.list(None);
match list_all {
POP3List {emails_metadata} => {
for i in emails_metadata.iter() {
println!("message_id: {}, message_size: {}", i.message_id, i.message_size);
}
},
_ => println!("There was an error listing your messages."),
}
let message_25 = email_socket.retr(25);
match message_25 {
POP3Message{raw} => {
for i in raw.iter() {
println!("{}", i);
}
},
_ => println!("There was an error getting your 25th message."),
}
email_socket.quit();
},
None => { println!("Please enter a URL for your server."); }
};
}
The Problem
Your problem boils down to the use of static since the keyword basically says "keep this object around forever". This means that the lifetime of place, without a doubt, will live long after input — forever vs the scope of the block.
fn get() -> Option<String> {
Some("hello world".to_owned())
}
fn main() {
let data = match get() {
Some(input) => { let place : &'static str = &input[..]; },
None => { }
};
}
In the above we try to make place a static reference to a str, other other words; a reference that exists for the entire duration of our program. input on the other hand will definitely not exist for this amount of time, and therefor we get an error diagnostic.
<anon>:7:54: 7:59 error: `input` does not live long enough
<anon>:7 Some(input) => { let place : &'static str = &input[..]; },
The Solution
Remove the use of static, effectively saying that the lifetime of place is that of the block (which is a subset of the lifetime associated with input).
fn get() -> Option<String> {
Some("hello world".to_owned())
}
fn main() {
let data = match get() {
Some(input) => { let place : &str = &input[..]; },
None => { }
};
}
Further Digging
As it turns out, POP3Stream::connect accepts a &'static str as its first argument; this is really bad design since it will only accept string-literals.
impl Pop3Stream {
pub fn connect(host: &'static str, ...) -> Result<POP3Stream> {
...
}
}
https://github.com/mattnenterprise/rust-pop3/blob/master/src/pop3.rs
You can, however, hack your way around the issue by intentionally leaking the resource—effectively making it live "forever". Please note the usage of unsafe, and keep in mind that this is—by language design—considered to be just that.
fn get () -> Option<String> {
Some("hello world".to_owned ())
}
fn connect (host : &'static str) {
/* ... */
}
fn main() {
let data = match get() {
Some(input) => {
let place : &'static str = unsafe {
use std::mem; let x = mem::transmute(&input as &str);
mem::forget (x); x
};
connect(place);
},
None => { }
};
}
Related
I've the following code I implemented to return an error when a string doesn't contain a match to something like "Mark, 55" to return an error. The compiler complains about my code Err(error) => Err(ParsePersonError::ParseInt(_))
use std::num::ParseIntError;
use std::str::FromStr;
#[derive(Debug, PartialEq)]
struct Person {
name: String,
age: usize,
}
// We will use this error type for the `FromStr` implementation.
#[derive(Debug, PartialEq)]
enum ParsePersonError {
// Empty input string
Empty,
// Incorrect number of fields
BadLen,
// Empty name field
NoName,
// Wrapped error from parse::<usize>()
ParseInt(ParseIntError),
}
// My implementation
impl FromStr for Person {
type Err = ParsePersonError;
fn from_str(s: &str) -> Result<Person, Self::Err> {
if s.len() == 0 {
Err(ParsePersonError::Empty)
}
else {
let v: Vec<&str> = s.split(",").collect();
println!("{:?}",v);
if &v[0]== &""{
Err(ParsePersonError::NoName)
}
else if v.len()!=2 {
Err(ParsePersonError::BadLen)
}
else {
let num = match v[1].parse::<usize>() {
Ok(n) => {
let name = v[0].to_string();
let age = n;
return Ok(Person {name,age})
},
Err(error) => Err(ParsePersonError::ParseInt(_))
};
Err(ParsePersonError::ParseInt(_))
}
}
}
}
However, the compiler doesn't complain about the same code in my test case.
ParsePersonError::ParseInt(_))
#[test]
fn missing_name_and_age() {
assert!(matches!(
",".parse::<Person>(),
Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_))
));
}
What am I missing?
If you de-sugar the match macro in test, it is something like
let result = ",".parse::<Person>();
let r = match result {
Err(ParsePersonError::NoName) => true,
Err(ParsePersonError::ParseInt(_)) => true,
_ => false,
};
assert!(r);
Essentially the '_' is to hold the value attached to ParseInt. Hence an assignment. This is what the compiler error message means.
I'm quite new in Rust and I'm having an issue with lifetimes that I believe I can understand what is happening and why, but can't get around in my head how can I solve it.
For simplicity I created this short "clone" of what I'm actually trying to do, but the real code is using asyc-stripe. Will annotate the example code with the real one in case is relevant.
There is the following structure:
// https://github.com/arlyon/async-stripe/blob/9f1a84144a23cc7b2124a1252ee15dc646ce0215/src/resources/generated/subscription.rs#L385
struct ObjectA<'a> {
field: i32,
object_b_id: Option<&'a str>,
}
// https://github.com/arlyon/async-stripe/blob/9f1a84144a23cc7b2124a1252ee15dc646ce0215/src/resources/generated/subscription.rs#L570
impl<'a> ObjectA<'a> {
fn new(field: i32) -> Self {
return Self {
field,
object_b_id: Default::default(),
};
}
}
// https://github.com/arlyon/async-stripe/blob/9f1a84144a23cc7b2124a1252ee15dc646ce0215/src/resources/generated/subscription.rs#L210
fn persist_obj_a(obj_a: ObjectA<'_>) {}
// ---
// https://github.com/arlyon/async-stripe/blob/9f1a84144a23cc7b2124a1252ee15dc646ce0215/src/resources/generated/payment_method.rs#L18
struct ObjectB {
id: ObjectBId,
}
// https://github.com/arlyon/async-stripe/blob/9f1a84144a23cc7b2124a1252ee15dc646ce0215/src/ids.rs#L518
struct ObjectBId {
value: String,
}
impl ObjectBId {
fn as_str(&self) -> &str {
return self.value.as_str();
}
}
// This is a wrapper around https://github.com/arlyon/async-stripe/blob/9f1a84144a23cc7b2124a1252ee15dc646ce0215/src/resources/generated/payment_method.rs#L128 that just returns the first one found (id any, hence the Option)
fn load_object_b() -> Option<ObjectB> {
return Some(ObjectB {
id: ObjectBId {
value: String::from("some_id"),
},
});
}
And what I'm trying to do is: load the ObjectB with load_object_b and use its ID into a ObjectA.
Ok, so on to my attempts.
First attempt
fn first_try(condition: bool) {
let mut obj_a = ObjectA::new(1);
if condition {
match load_object_b() {
Some(obj_b) => obj_a.object_b_id = Some(obj_b.id.as_str()),
None => (),
}
}
persist_obj_a(obj_a);
}
In here I get
obj_b.id does not live long enough
Which I can understand, since from what I can understand the obj_b only exists during the match arm and is droped by the end of it.
Second attempt
fn second_try(condition: bool) {
let mut obj_a = ObjectA::new(1);
if condition {
let obj_b = load_object_b();
match obj_b {
Some(ref obj_b) => obj_a.object_b_id = Some(obj_b.id.as_str()),
None => (),
}
}
persist_obj_a(obj_a);
}
Here I get
obj_b.0 does not live long enough
Which I guess it is still the same idea, just in a different place. Since again, from my understanding, obj_b now only lives within the scope of the if condition.
Third and last attempt
I ended up "solving" it with:
fn third_try(condition: bool) {
let mut obj_a = ObjectA::new(1);
let obj_b = load_object_b();
let obj_b_id = match obj_b {
Some(ref obj_b) => Some(obj_b.id.as_str()),
None => None,
};
if condition {
obj_a.object_b_id = obj_b_id;
}
persist_obj_a(obj_a);
}
In here I moved the obj_b to have the same lifetime as obj_a. So it solves the issue that I was having.
My problem with this solution is that I feel that I'm wasting resource doing the (possible expensive) request to load_object_b even if I'm not gonna use it based on the condition.
Not sure if I'm missing something very obvious or just going on the overall wrong direction, but would appreciate some light on what I might be doing wrong.
This should work, I think:
fn third_try(condition: bool) {
let mut obj_a = ObjectA::new(1);
let obj_b = if condition { load_object_b() } else { None };
obj_a.object_b_id = obj_b.as_ref().map (|o| o.id.as_str());
persist_obj_a(obj_a);
}
Rust allows you to have conditionally initialized variables. You can declare obj_b ouside of the if, but only initialize it inside the if. The compiler will ensure you can use it only if it is initialized.
fn second_try(condition: bool) {
let mut obj_a = ObjectA::new(1);
let obj_b;
if condition {
obj_b = load_object_b();
match obj_b {
Some(ref obj_b) => obj_a.object_b_id = Some(obj_b.id.as_str()),
None => (),
}
}
persist_obj_a(obj_a);
}
Introduction
I'm learning rust and have been trying to find the right signature for using multiple Results in a single function and then returning either correct value, or exit the program with a message.
So far I have 2 different methods and I'm trying to combine them.
Context
This is what I'm trying to achieve:
fn blur(image: DynamicImage, amount: &str) -> DynamicImage {
let amount = parse_between_or_error_out("blur", amount, 0.0, 10.0);
image.brighten(amount)
}
This is what I have working now, but would like to refactor.
fn blur(image: DynamicImage, amount: &str) -> DynamicImage {
match parse::<f32>(amount) {
Ok(amount) => {
verify_that_value_is_between("blur", amount, 0.0, 10.0);
image.blur(amount)
}
_ => {
println!("Error");
process::exit(1)
}
}
}
Combining these methods
Now here's the two working methods that I'm trying to combine, to achieve this.
fn parse<T: FromStr>(value: &str) -> Result<T, <T as FromStr>::Err> {
value.parse::<T>()
}
fn verify_that_value_is_between<T: PartialOrd + std::fmt::Display>(
name: &str,
amount: T,
minimum: T,
maximum: T,
) {
if amount > maximum || amount < minimum {
println!(
"Error: Expected {} amount to be between {} and {}",
name, minimum, maximum
);
process::exit(1)
};
println!("- Using {} of {:.1}/{}", name, amount, maximum);
}
Here's what I tried
I have tried the following. I realise I'm likely doing a range of things wrong. This is because I'm still learning Rust, and I'd like any feedback that helps me learn how to improve.
fn parse_between_or_error_out<T: PartialOrd + FromStr + std::fmt::Display>(
name: &str,
amount: &str,
minimum: T,
maximum: T,
) -> Result<T, <T as FromStr>::Err> {
fn error_and_exit() {
println!(
"Error: Expected {} amount to be between {} and {}",
name, minimum, maximum
);
process::exit(1);
}
match amount.parse::<T>() {
Ok(amount) => {
if amount > maximum || amount < minimum {
error_and_exit();
};
println!("- Using {} of {:.1}/{}", name, amount, maximum);
amount
}
_ => {
error_and_exit();
}
}
}
Currently this looks quite messy, probably I'm using too many or the wrong types and the error needs to be in two places (hence the inlined function, which I know is not good practice).
Full reproducible example.
The question
How to best combine logic that is using a Result and another condition (or Result), exit with a message or give T as a result?
Comments on any of the mistakes are making are very welcome too.
You can use a crate such as anyhow to bubble your events up and handle them as needed.
Alternatively, you can write your own trait and implement it on Result.
trait PrintAndExit<T> {
fn or_print_and_exit(&self) -> T;
}
Then use it by calling the method on any type that implements it:
fn try_get_value() -> Result<bool, MyError> {
MyError { msg: "Something went wrong".to_string() }
}
let some_result: Result<bool, MyError> = try_get_value();
let value: bool = some_result.or_print_and_exit();
// Exits with message: "Error: Something went wrong"
Implementing this trait on Result could be done with:
struct MyError {
msg: String,
}
impl<T> PrintAndExit<T> for Result<T, MyError> {
fn or_print_and_exit(&self) -> T {
match self {
Ok(val) => val,
Err(e) => {
println!("Error: {}", e.msg);
std::process::exit(1);
},
}
}
}
Here are a few DRY tricks.
tl;dr:
Convert other Errors into your unified error type(s) with impl From<ExxError> for MyError;
In any function that may result in an Error, use ? as much as you can. Return Result<???, MyError> (*). ? will utilize the implicit conversion.
(*) Only if MyError is an appropriate type for the function. Always create or use the most appropriate error types. (Kinda obvious, but people often treat error types as a second-class code, pun intended)
Recommendations are in the comments.
use std::error::Error;
use std::str::FromStr;
// Debug and Display are required by "impl Error" below.
#[derive(Debug)]
enum ProcessingError {
NumberFormat{ message: String },
NumberRange{ message: String },
ProcessingError{ message: String },
}
// Display will be used when the error is printed.
// No need to litter the business logic with error
// formatting code.
impl Display for ProcessingError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ProcessingError::NumberFormat { message } =>
write!(f, "Number format error: {}", message),
ProcessingError::NumberRange { message } =>
write!(f, "Number range error: {}", message),
ProcessingError::ProcessingError { message } =>
write!(f, "Image processing error: {}", message),
}
}
}
impl Error for ProcessingError {}
// FromStr::Err will be implicitly converted into ProcessingError,
// when ProcessingError is needed. I guess this is what
// anyhow::Error does under the hood.
// Implement From<X> for ProcessingError for every X error type
// that your functions like process_image() may encounter.
impl From<FromStr::Err> for ProcessingError {
fn from(e: FromStr::Err) -> ProcessingError {
ProcessingError::NumberFormat { message: format!("{}", e) }
}
}
pub fn try_parse<T: FromStr>(value: &str) -> Result<T, ProcessingError> {
// Note ?. It will implicitly return
// Err(ProcessingError created from FromStr::Err)
Ok (
value.parse::<T>()?
)
}
// Now, we can have each function only report/handle errors that
// are relevant to it. ? magically eliminates meaningless code like
// match x { ..., Err(e) => Err(e) }.
pub fn parse_between<T>(value: &str, min_amount: T, max_amount: T)
-> Result<T, ProcessingError>
where
T: FromStr + PartialOrd + std::fmt::Display,
{
let amount = try_parse::<T>(value)?;
if amount > max_amount || amount < min_amount {
Err(ProcessingError::NumberRange {
message: format!(
"Expected value to be between {} and {} but received {}",
min_amount,
max_amount,
amount)
})
} else {
Ok(amount)
}
}
main.rs
use image::{DynamicImage};
use std::fmt::{Debug, Formatter, Display};
fn blur(image: DynamicImage, value: &str)
-> Result<DynamicImage, ProcessingError>
{
let min_amount = 0.0;
let max_amount = 10.0;
// Again, note ? in the end.
let amount = parse_between(value, min_amount, max_amount)?;
image.blur(amount)
}
// All processing extracted into a function, whose Error
// then can be handled by main().
fn process_image(image: DynamicImage, value: &str)
-> Result<DynamicImage, ProcessingError>
{
println!("applying blur {:.1}/{:.1}...", amount, max_amount);
image = blur(image, value);
// save image ...
image
}
fn main() {
let mut image = DynamicImage::new(...);
image = match process_image(image, "1") {
Ok(image) => image,
// No need to reuse print-and-exit functionality. I doubt
// you want to reuse it a lot.
// If you do, and then change your mind, you will have to
// root it out of all corners of your code. Better return a
// Result and let the caller decide what to do with errors.
// Here's a single point to process errors and exit() or do
// something else.
Err(e) => {
println!("Error processing image: {:?}", e);
std::process::exit(1);
}
}
}
Sharing my results
I'll share my results/answer as well for other people who are new to Rust. This answer is based on that of #Acidic9's answer.
The types seem to be fine
anyhow looks to be the de facto standard in Rust.
I should have used a trait and implement that trait for the Error type.
I believe the below example is close to what it might look like in the wild.
// main.rs
use image::{DynamicImage};
use app::{parse_between, PrintAndExit};
fn main() {
// mut image = ...
image = blur(image, "1")
// save image
}
fn blur(image: DynamicImage, value: &str) -> DynamicImage {
let min_amount = 0.0;
let max_amount = 10.0;
match parse_between(value, min_amount, max_amount).context("Input error") {
Ok(amount) => {
println!("applying blur {:.1}/{:.1}...", amount, max_amount);
image.blur(amount)
}
Err(error) => error.print_and_exit(),
}
}
And the implementation inside the apps library, using anyhow.
// lib.rs
use anyhow::{anyhow, Error, Result};
use std::str::FromStr;
pub trait Exit {
fn print_and_exit(self) -> !;
}
impl Exit for Error {
fn print_and_exit(self) -> ! {
eprintln!("{:#}", self);
std::process::exit(1);
}
}
pub fn try_parse<T: FromStr>(value: &str) -> Result<T, Error> {
match value.parse::<T>() {
Ok(value) => Ok(value),
Err(_) => Err(anyhow!("\"{}\" is not a valid value.", value)),
}
}
pub fn parse_between<T>(value: &str, min_amount: T, max_amount: T) -> Result<T, Error>
where
T: FromStr + PartialOrd + std::fmt::Display,
{
match try_parse::<T>(value) {
Ok(amount) => {
if amount > max_amount || amount < min_amount {
return Err(anyhow!(
"Expected value to be between {} and {} but received {}",
min_amount,
max_amount,
amount
));
};
Ok(amount)
}
Err(error) => Err(error),
}
}
Hopefully seeing this full implementation will help someone out there.
Source code.
so, if I return this
self.string_ref.unwrap().as_ref()
compiler will say
error[E0515]: cannot return value referencing temporary value
returns a value referencing data owned by the current function
if I return this
*self.string_ref.unwrap().as_ref()
the compiler will say
error[E0507]: cannot move out of borrowed content
this is just drove me crazy
here is the code: (playground)
use std::ptr::NonNull;
struct A {
string_ref: Option<NonNull<String>>,
}
struct Number {
num: i32
}
impl A {
fn hello() {
}
fn give_me_string(&self) -> String {
unsafe {
*self.string_ref.unwrap().as_ref()
}
}
}
fn main() {
let a = A {
string_ref: NonNull::new(&mut String::from("hello world") as *mut String)
};
let t = a.give_me_string();
println!("{}", t)
}
Stripping your example to the bare minimum:
struct A {
string_ref: Option<NonNull<String>>,
}
impl A {
fn give_me_string(&self) -> String {
unsafe {
*self.string_ref.unwrap().as_ref()
}
}
}
There are a few errors here:
The most obvious one is that you're trying to take ownership of self.string_ref, even though you've only borrowed self.
To solve this you'll want to use a match statement, which allows you to destructure self.string_ref and not consume it:
fn give_me_string(&self) -> String {
unsafe {
match self.string_ref {
Some(x) => x.as_ref(),
None => panic!("Had no `string_ref`!")
}
}
}
as_ref returns &T, so you can't return an owned string, instead you need to either clone it and then return an owned string, or take reference to it:
//Option one: Clone contents
match self.string_ref {
Some(ref x) => x.as_ref().clone(),
_ => //...
}
//Option two: Return reference.
fn give_me_string(&self) -> &str {
unsafe {
match &self.string_ref {
Some(x) => x.as_ref() as _,
_ => //...
}
}
}
To address another problem mentioned in the comments, you have the following statement in your main function:
string_ref: NonNull::new(&mut String::from("hello world") as *mut String)
This will cause UB due to its nature. You are forming a String by using String::from, but are not storing its value anywhere and are instead immediately casting into a pointer. This will free the String at the end of the line, causing UB.
So I basically figured out what's going on, thanks to #Optimistic Peach
fn give_me_string(&self) -> &String {
unsafe {
match self.string_ref {
Some(x) => &*(x.as_ptr() as *const _), //without ref
Some(ref x) => x.as_ptr(), // with ref
None => panic!("hello?")
}
}
}
I'm trying to build a basic web crawler in Rust, which I'm trying to port to html5ever. As of right now, I have a function with a struct inside that is supposed to return a Vec<String>. It gets this Vec from the struct in the return statement. Why does it always return an empty vector? (Does it have anything to do with the lifetime parameters?)
fn find_urls_in_html<'a>(
original_url: &Url,
raw_html: String,
fetched_cache: &Vec<String>,
) -> Vec<String> {
#[derive(Clone)]
struct Sink<'a> {
original_url: &'a Url,
returned_vec: Vec<String>,
fetched_cache: &'a Vec<String>,
}
impl<'a> TokenSink for Sink<'a> {
type Handle = ();
fn process_token(&mut self, token: Token, _line_number: u64) -> TokenSinkResult<()> {
trace!("token {:?}", token);
match token {
TagToken(tag) => {
if tag.kind == StartTag && tag.attrs.len() != 0 {
let _attribute_name = get_attribute_for_elem(&tag.name);
if _attribute_name == None {
return TokenSinkResult::Continue;
}
let attribute_name = _attribute_name.unwrap();
for attribute in &tag.attrs {
if &attribute.name.local != attribute_name {
continue;
}
trace!("element {:?} found", tag);
add_urls_to_vec(
repair_suggested_url(
self.original_url,
(&attribute.name.local, &attribute.value),
),
&mut self.returned_vec,
&self.fetched_cache,
);
}
}
}
ParseError(error) => {
warn!("error parsing html for {}: {:?}", self.original_url, error);
}
_ => {}
}
return TokenSinkResult::Continue;
}
}
let html = Sink {
original_url: original_url,
returned_vec: Vec::new(),
fetched_cache: fetched_cache,
};
let mut byte_tendril = ByteTendril::new();
{
let tendril_push_result = byte_tendril.try_push_bytes(&raw_html.into_bytes());
if tendril_push_result.is_err() {
warn!("error pushing bytes to tendril: {:?}", tendril_push_result);
return Vec::new();
}
}
let mut queue = BufferQueue::new();
queue.push_back(byte_tendril.try_reinterpret().unwrap());
let mut tok = Tokenizer::new(html.clone(), std::default::Default::default()); // default default! default?
let feed = tok.feed(&mut queue);
return html.returned_vec;
}
The output ends with no warning (and a panic, caused by another function due to this being empty). Can anyone help me figure out what's going on?
Thanks in advance.
When I initialize the Tokenizer, I use:
let mut tok = Tokenizer::new(html.clone(), std::default::Default::default());
The problem is that I'm telling the Tokenizer to use html.clone() instead of html. As such, it is writing returned_vec to the cloned object, not html. Changing a few things, such as using a variable with mutable references, fixes this problem.