在Rust traits中公开实现细节

在Rust traits中公开实现细节,rust,Rust,我是Rust新手,来自Java世界,我想像玩Java接口一样玩Rust特性。 我设想了以下需要: 我必须能够保存用户firstname,lastname在数据库的某个地方,一个文件 我可以把它们都拿来 我开始定义我想要的特质: 特征用户数据库{ fn获取所有&self->Result; fn保存和修改自身,用户:&用户->结果; } 您可以看到,当我声明get_all函数时,我没有提到需要对self进行可变借用,即&mut self 然后我决定用文件功能实现这个特性。请在最后找到完整的代码 令我

我是Rust新手,来自Java世界,我想像玩Java接口一样玩Rust特性。 我设想了以下需要:

我必须能够保存用户firstname,lastname在数据库的某个地方,一个文件 我可以把它们都拿来 我开始定义我想要的特质:

特征用户数据库{ fn获取所有&self->Result; fn保存和修改自身,用户:&用户->结果; } 您可以看到,当我声明get_all函数时,我没有提到需要对self进行可变借用,即&mut self

然后我决定用文件功能实现这个特性。请在最后找到完整的代码

令我惊讶的是,当我读取文件内容时,我必须声明self是可变的。原因如下:

这让我很恼火,因为如果我这样做,我必须在特质自我中声明为可变的,即使我正在阅读数据。我觉得trait中的实现细节有漏洞

我认为我的方法是无效的,或者不习惯于生锈。你将如何做到这一点

以下是完整的代码:

///这段代码不可编译 ///编译器告诉我们将self设置为可变的 使用std::fs::File; 使用std::fs::OpenOptions; 使用std::io; 使用std::path::path; 使用std::io::Read; 使用std::io::Write; 结构用户{ pub firstname:String, pub lastname:String, } 特征用户数据库{ fn获取所有&self->Result; fn保存和修改自身,用户:&用户->结果; } 结构FsUserDb{ 发布文件:文件, } impl-FsUserDb{ fn newfilename:&str->Result{ 如果路径::newfilename.exe存在{ 让file=OpenOptions::new .真的吗 .WriteRue .openfilename?; OkFsUserDb{file} }否则{ OkFsUserDb{ 文件:文件::createfilename?, } } } } FsUserDb的impl UserDb{ fn获取所有&self->Result{ 让mut contents=String::new; self.file.read_to_string&mut contents?; 让用户=内容 线 .map | line | line.split;.collect:: .map |分割线|用户{ 名字:拆分\u行[0]。到\u字符串, 姓氏:拆分\u行[1]。到\u字符串, } 收集 奥克斯 } fn保存和修改自身,用户:&用户->结果{ 让用户输入字符串= 格式!{},{},user.firstname,user.lastname; 匹配self.file.writeuser\u string.as\u字节{ 好的, Erre=>Erre } } } fn干线{ 让db=FsUserDb::new/tmp/user db; } 阅读所需的可变借阅,您对此无能为力

要解决您的问题,我可以想到三种选择:

按照编译器的建议修改trait to&mut self上的签名。这是最清晰的解决方案,我不知道你为什么不喜欢它

使用像RefCell这样的内部易变性,并在需要的地方获取易变文件。使用此解决方案,您甚至不需要声明“另存为可变”,但会增加一些运行时成本。我确实建议阅读关于RefCell的内容,因为这可能会在以后引入其他类型的错误

存储文件名,而不是文件处理程序本身,并在适当时打开/关闭它。这样,您还可以使用不可变保存


虽然RefCell的运行时成本很小,但与读取文件相比,这一成本可以忽略不计。我并不是真的不喜欢在签名中加入&mut self,我只是觉得在读取数据时说有变异是很奇怪的。我想我会选择你提到的第一个解决方案,遵循编译器提示。还感谢您提供其他选项:。