After studying the language I decided to create something with it, and I already realized that creating classes is a lot of work, I was racking my brain to be able to define a std :: fs :: File in my class to be started after the constructor and I was unsuccessful. I feel that Rust forces you to start everything as soon as possible, even when that is not desirable or possible at the moment.
Sorry for the bad English and in case my doubt doesn't make much sense.
If you want to create a File
later, you can use an Option<File>
.
Rust forces to you acknowledge whenever something could possibly not be there by making it an Option
. In this way we avoid the null
value throughout the entire language and you never have to do checks like if something != null
all over the place because you never know when something might possibly be null.
By making something an Option
you tell Rust that this could potentially be a None
variant and not actually Some(File)
yet. This means that you will have to .unwrap()
that option or use an if let
statement to get to that file later, though, because Rust also forces you to acknowledge that the file might not be there yet.
For instance:
struct MyClass {
file: Option<std::fsFile>
}
impl MyClass {
fn new(path: String) -> Self {
MyClass {
path,
// File starts off None
file: None,
}
}
fn load_file(&mut self) {
// We later set the file to Some(File)
self.file = Some(std::fs::OpenOptions::new().read(true).path(self.path).open().unwrap());
}
fn read_data() -> String {
// We have to check whether or not the file is Some(file) first
// before we can get to the file. This is similar to checking
// `if file != null` in other languages, but in Rust we can't
// forget to do it.
if let Some(file) = self.file {
let data = String::new();
file.read_to_string(&mut data).unwrap();
// return the data
data
// We have to figure out what to do in case the file is not
// there yet.
} else {
// We could panic...
panic!("You can't read the file data before you've loaded it!");
// or maybe we could just return an empty string
String::new()
// The best thing to do would be to return a `Result` which
// would clearly indicate a potential failure, but that is
// another lesson ;)
}
}
}
Using Option with Box solved my lazy init problem well. I forgot to describe the issue of files better. Initially I wanted to use File but then I wanted to use the "everything is a file" approach. Thanks for the tip and the explanation.
use std::io::{BufReader, Read};
use std::fs::File;
struct SourceTranslator {
reader_impl: Option<Box<dyn Read>>
}
impl SourceTranslator {
pub fn new() -> Self {
Self { reader_impl: None }
}
pub fn reader(&mut self, reader_impl: Box<dyn Read>) {
self.reader_impl = Some(reader_impl);
}
pub fn translate(&mut self) {
if let Some(r) = self.reader_impl.as_mut(){
let mut buf:[u8;128] = [0; 128];
r.read(&mut buf);
println!("{}", String::from_utf8_lossy(&buf));
}
}
}
#[test]
fn rust_file() {
let f = File::open("hello.msk").unwrap();
let mut t = SourceTranslator::new();
t.reader(Box::new(BufReader::new(f)));
t.translate();
}
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.