使用 `pop3::POP3Stream::connect` 连接到给定 `host` 的运行时?

Using `pop3::POP3Stream::connect` to connect to runtime given `host`?

我正在尝试读取用户的输入,然后将其用作 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."); }
    };
}

问题

您的问题归结为 static 的使用,因为关键字基本上是 "keep this object around forever"。这意味着 place 的生命周期毫无疑问会在 input 之后很长一段时间——永远 vs 块的范围。

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

在上面我们尝试让place成为staticstr的引用,换句话说;在我们计划的整个持续时间内都存在的参考。 input 另一方面,这段时间肯定不会存在,因此我们得到错误诊断。

<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 接受一个 &'static str 作为它的第一个参数;这是非常糟糕的设计,因为它只接受字符串文字。

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

但是,您可以通过故意泄露资源来解决问题——有效地使其生效 "forever"。请注意 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 => { }
    };   
}