公开Rust特质的实现细节

问题描述 投票:0回答:1

我是Rust的新手,来自Java世界,我想像使用Java接口一样使用Rust特质。我想象了以下需求:

  • 我必须能够将用户(名,姓)保存在某个地方(在数据库,文件中)
  • 我可以全部获取

我开始定义我想要的特征:

trait UserDb {
    fn get_all(&self) -> Result<Vec<User>, io::Error>;

    fn save(&mut self, user: &User) -> Result<(), io::Error>;
}

[您可以看到,当我声明get_all函数时,我没有提到需要在self(即&mut self)上进行可变借用。

然后,我决定通过File功能实现此特征(请在末尾找到完整的代码)。

[让我惊讶的是,当我读取文件的内容时,我必须声明self为可变的。 (这是为什么Why does a File need to be mutable to call Read::read_to_string?的原因)

[这很烦我,因为如果这样做,即使正在读取数据,我也必须在特征self中声明为可变的。我觉得特质中存在实施细节泄漏。

我认为我的方法在Rust中无效或惯用。您将如何实现这一目标?

这里是完整代码:

///THIS CODE DOESNT COMPILE
///THE COMPILER TELLS TO MAKE self AS MUTABLE
use std::fs::File;
use std::fs::OpenOptions;
use std::io;
use std::path::Path;
use std::io::Read;
use std::io::Write;

struct User {
    pub firstname: String,
    pub lastname: String,
}

trait UserDb {
    fn get_all(&self) -> Result<Vec<User>, io::Error>;

    fn save(&mut self, user: &User) -> Result<(), io::Error>;
}

struct FsUserDb {
    pub file: File,
}

impl FsUserDb {
    fn new(filename: &str) -> Result<FsUserDb, io::Error> {
        if Path::new(filename).exists() {
            let file = OpenOptions::new()
                .append(true)
                .write(true)
                .open(filename)?;

            Ok(FsUserDb { file })
        } else {
            Ok(FsUserDb {
                file: File::create(filename)?,
            })
        }
    }
}

impl UserDb for FsUserDb {
    fn get_all(&self) -> Result<Vec<User>, io::Error> {
        let mut contents = String::new();

        self.file.read_to_string(&mut contents)?;

        let users = contents
            .lines()
            .map(|line| line.split(";").collect::<Vec<&str>>())
            .map(|split_line| User {
                firstname: split_line[0].to_string(),
                lastname: split_line[1].to_string(),
            })
            .collect();

        Ok(users)
    }

    fn save(&mut self, user: &User) -> Result<(), io::Error> {
        let user_string =
            format!("{},{}", user.firstname, user.lastname);

        match self.file.write(user_string.as_bytes()) {
            Ok(_) => Ok(()),
            Err(e) => Err(e)
        }
    }
}

fn main() {
    let db = FsUserDb::new("/tmp/user-db");
}

rust
1个回答
0
投票

[read必需的可变借位,对此您无能为力。

© www.soinside.com 2019 - 2024. All rights reserved.