2016-07-05 76 views
1

我有一个结构UrlShortener用于在不同的地方不同的对象平等的寿命

pub struct UrlShortener { 
    client: hyper::Client, 
} 
impl UrlShortener { 
    pub fn new() -> UrlShortener { 
     UrlShortener { 
      client: hyper::Client::new(), 
     } 
    } 

    pub fn get(&self, url: &str) -> Result<String, Error> { 
     let mut response = MyProvider.request(url, &self.client).send().unwrap(); 
     /// ... 
    } 
} 

MyProvider看起来是这样的:

pub trait Provider { 
    fn name(&self) -> &str; 
    fn request(&self, url: &str, client: &hyper::Client) -> hyper::client::RequestBuilder; 
} 

pub struct MyProvider; 
impl Provider for MyProvider { 
    fn name(&self) -> &str { 
     "myprovider" 
    } 

    fn request(&self, url: &str, client: &hyper::Client) -> hyper::client::RequestBuilder { 
     client.get(&format!("http://example.com/create.php?format=simple&url={}", url)) 
    } 
} 

的我想在第一次没有成功将其编译:

src/lib.rs:21:16: 21:19 error: cannot infer an appropriate lifetime for autoref due to conflicting requirements [E0495] 
src/lib.rs:21   client.get(&format!("http://example.com/create.php?format=simple&url={}", url)) 
          ^~~ 
src/lib.rs:20:5: 22:6 help: consider using an explicit lifetime parameter as shown: fn request<'a>(&'a self, url: &str, client: &'a hyper::Client) 
-> hyper::client::RequestBuilder 
src/lib.rs:20  fn request(&self, url: &str, client: &hyper::Client) -> hyper::client::RequestBuilder { 
src/lib.rs:21   client.get(&format!("http://example.com/create.php?format=simple&url={}", url)) 
src/lib.rs:22  } 
error: aborting due to previous error 
error: Could not compile `urlshortener`. 

我已经根据编译器的建议改变它,它是w没问题。

fn request<'a>(&'a self, url: &str, client: &'a hyper::Client) -> hyper::client::RequestBuilder { 
    client.get(&format!("http://example.com/create.php?format=simple&url={}", url)) 
} 

这里的问题是为什么它工作?是什么在我的脑海:

'aProvider寿命为self是从client: &hyper::Client寿命不同,因为这些对象是在不同的地方:MyProvider是在栈上和client是方法的结构的场我用。

所以我认为编译器会成功编译它,但它可能会导致运行时错误或崩溃。我错了吗?

“正确的”从我的角度来看的解决办法是:

fn request<'a, 'b>(&'a self, url: &str, client: &'b hyper::Client) -> hyper::client::RequestBuilder { 

回答

5

所以我觉得编译器编译它成功,但它可能会导致运行时错误或崩溃。

除非你使用了一些unsafe {}的代码,否则这在Rust中不会发生。 Rust总是静态检查边界,无论变量是堆栈还是堆,或者是字段或其他,都无关紧要。

至于锈的建议:既然RequestBuilder具有有效期本身有以下功能:

fn request(&self, url: &str, client: &hyper::Client) -> hyper::client::RequestBuilder; 

相当于:因为elisions rules

fn request<'a, 'b, 'c>(&'a self, url: &'b str, client: &'c hyper::Client) -> hyper::client::RequestBuilder<'a>; 
//      ^^                     ^^ 

。请注意该示例中的重要规则:

如果有多个输入寿命,但其中之一是&self&mut self,自我的寿命分配给所有的消隐输出寿命。

这就是当Rust给你一个误导性的建议。在你的函数中,返回值取决于client,但实际上并不在self上。 Rust建议你给selfclient同样的生命期(即。'a == 'c):

fn request<'a, 'b>(&'a self, url: &'b str, client: &'a hyper::Client) -> hyper::client::RequestBuilder<'a>; 
//     ^^        ^^             ^^ 

但是这将是足够了:

fn request<'a, 'b, 'c>(&'a self, url: &'b str, client: &'c hyper::Client) -> hyper::client::RequestBuilder<'c>; 
//      ^^        ^^             ^^ 

可与省音写成:

fn request<'c>(&self, url: &str, client: &'c hyper::Client) -> hyper::client::RequestBuilder<'c>; 
//          ^^             ^^ 
相关问题