简体   繁体   English

返回对可选结构成员的可变引用

[英]Returning mutable reference to an optional struct member

I want to make lazy connection to a Redis database. 我想与Redis数据库建立延迟连接。 I have a Db struct, which holds the Redis Client . 我有一个Db结构,其中包含Redis Client By default it is None . 默认情况下为None Here is example code in Python: 这是Python中的示例代码:

import redis


class Db:

    def __init__(self):
        self.client = None

    def get_client(self):
        if self.client is None:
            self.client = redis.StrictRedis(host='127.0.0.1')
        return self.client

I tried this 我试过了

extern crate redis;

use redis::Client;

struct Db {
    client: Option<Client>,
}

impl Db {
    fn new() -> Db {
        Db { client: None }
    }

    fn get_client(&mut self) -> Result<&Client, &'static str> {
        if let Some(ref client) = self.client {
            Ok(client)
        } else {
            let connection_string = "redis://127.0.0.1";
            match Client::open(connection_string) {
                Ok(client) => {
                    self.client = Some(client);
                    Ok(&self.client.unwrap())
                }
                Err(err) => Err("Error!"),
            }
        }
    }
}

fn main() {
    let mut db = Db::new();
    db.get_client();
}

And I have compile errors. 而且我有编译错误。 I almost understand what compiler says, but I don't know how to solve the problem. 我几乎理解编译器的内容,但是我不知道如何解决该问题。

    error: borrowed value does not live long enough
  --> src/main.rs:28:29
   |
28 |                         Ok(&self.client.unwrap())
   |                             ^^^^^^^^^^^^^^^^^^^^ does not live long enough
29 |                     },
   |                     - temporary value only lives until here
   |
note: borrowed value must be valid for the anonymous lifetime #1 defined on the body at 19:66...
  --> src/main.rs:19:67
   |
19 |         fn get_client(&mut self) -> Result<&Client, &'static str> {
   |                                                                   ^

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:28:29
   |
28 |                         Ok(&self.client.unwrap())
   |                             ^^^^ cannot move out of borrowed content

If you call unwrap() you move T out of the Option . 如果调用unwrap() ,则将T移出Option Since you only borrowed self this leads to the cannot move out of borrowed content error. 由于您仅借用self因此导致cannot move out of borrowed content错误。

If you want to borrow the value inside an Option<T> you can use the as_ref method: 如果要在Option<T>借入值,则可以使用as_ref方法:

extern crate redis;

use redis::Client;

struct Db {
    client: Option<Client>,
}

impl Db {
    fn new() -> Db {
        Db { client: None }
    }

    fn get_client(&mut self) -> Result<&Client, &'static str> {
        if let Some(ref client) = self.client {
            Ok(client)
        } else {
            let connection_string = "redis://127.0.0.1";
            match Client::open(connection_string) {
                Ok(client) => {
                    self.client = Some(client);
                    Ok(self.client.as_ref().unwrap())
                }
                Err(_) => Err("Error!"),
            }
        }
    }
}

fn main() {
    let mut db = Db::new();
    db.get_client().expect("get_client failed");
}

So, there is solution, to which I came 因此,我想到了解决方案

struct Db {
    connection: Option<Connection>,
    host: String,
    port: u16,
    db: u8,
}


impl Db {

    fn new(host: String, port: u16, db: u8) -> Db {
        Db {
            host: host,
            port: port,
            db: db,
            connection: None,
        }
    }

    fn get_connection(&mut self) -> RedisResult<&Connection> {
        if let Some(ref connection) = self.connection {
            Ok(connection)
        }
        else {
            let connection_string = format!("redis://{0}:{1}/{2}", self.host, self.port, self.db);
            self.connection = Some(
                Client::open(connection_string.as_ref())?.get_connection()?);
            Ok(self.connection.as_ref().unwrap())
        }
    }

    fn keys(&mut self) -> RedisResult<Vec<String>> {
        let key_iter: redis::Iter<String> = self.get_connection()?.scan()?;
        Ok(key_iter.collect())
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM