2

我正在尝试读取用户的输入,然后将其用作 POP3 库的 URL。将String我得到的转换为字符串切片时,它的寿命不够长,无法使用。这对我来说很奇怪,原因有两个:

  1. 因为使用 POP3 对象的所有东西都在同一个块内,所以 str 切片的生命周期应该是整个块的生命周期,这将涵盖所有内容

  2. 我已经尝试了几乎所有我能想到的不同代码配置,但无济于事,我每次都得到相同的错误。

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."); }
    };
}
4

1 回答 1

2

问题

您的问题归结为使用,static因为关键字基本上说“永远保留这个对象”place毫无疑问,这意味着 的生命周期将在很长一段时间之后input——永远块的范围相比。

fn get() -> Option<String> {
    Some("hello world".to_owned())
}
fn main() {
    let data = match get() {
        Some(input) => { let place : &'static str = &input[..]; },
        None        => { }
    };
}

在上面我们尝试引用 a place,换句话说;在我们程序的整个过程中都存在的参考。另一方面,在这段时间内肯定不会存在,因此我们会得到错误诊断。staticstrinput

<anon>:7:54: 7:59 error: `input` does not live long enough
<anon>:7         Some(input) => { let place : &'static str = &input[..]; },

解决方案

删除 的使用static,有效地表示 的生命周期place是块的生命周期(它是与 关联的生命周期的子集input)。

fn get() -> Option<String> {
    Some("hello world".to_owned())
}
fn main() {
    let data = match get() {
        Some(input) => { let place : &str = &input[..]; },
        None        => { }
    };   
}


进一步挖掘

事实证明,POP3Stream::connect接受 a&'static str作为它的第一个参数;这是一个非常糟糕的设计,因为它只接受字符串文字。

impl Pop3Stream {
    pub fn connect(host: &'static str, ...) -> Result<POP3Stream> {
        ...
    }
}

但是,您可以通过故意泄漏资源来解决问题 - 有效地使其“永远”存在。请注意 的用法unsafe,并记住,根据语言设计,这就是这样。

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 => { }
    };   
}
于 2015-10-08T14:52:01.720 回答