Piece of code how encapsulate in Struct?

Hi, this piece of code work fine for me.
but How i can encapsulate in Struct and inicialize loading data from info.txt ??

MY PIECE OF CODE WORK FINE!

// .begin info.txt
            //let mut original_title: &str = "";
            let mut original_title:Option<String> = None;
            //let mut year: &str = "";
            let mut year:Option<String> = None;
            //let mut country: &str = "";
            let mut country:Option<String> = None;
            let mut synopsis:Option<String> = None;
            let mut cast:Option<String> = None;
            let mut genre:Option<String> = None;
            
            if info_txt == true {            
                //let reader = "\u{feff}\r\nOriginal Title\r\n Plane\r\nAKA\r\n The Plane\r\nSaving General Tang\r\nYear\r\n 2022\r\nCountry\r\n United States\r\n";                            
                let filename = format!("{}/info.txt", movie_path.display());
                //println!("file name info: {}", &filename);
                let reader = fs::read_to_string(filename)
                                    .expect("Except: file info.txt does not exist");
                            
                for line in lines {
                    if line.contains("Original Title") {
                        //original_title = find(&reader, &line).unwrap().trim();
                        original_title = Some(find(&reader, &line).unwrap().trim().to_string());
                    } else if line.contains("Year") {
                        year = Some(find(&reader, &line).unwrap().trim().to_string());
                    } else if line.contains("Country") {
                        country = Some(find(&reader, &line).unwrap().trim().to_string());
                    } else if line.contains("Synopsis") {
                        synopsis = Some(find(&reader, &line).unwrap().trim().to_string());
                    } else if line.contains("Cast") {
                        cast = Some(find(&reader, &line).unwrap().trim().to_string());
                    } else if line.contains("Genre") {
                        genre = Some(find(&reader, &line).unwrap().trim().to_string());
                    }

                }
    
                //println!("Original title is -> {}", original_title);  :-(
                println!("Original title is -> {}", original_title.clone().unwrap());
//                 println!("Year is -> {}", year);
//                 println!("Country is -> {}", country);
                

            } // end if info_txt
MY IDEA IS THIS :woozy_face::
struct Section_info {
    original_title:Option<String>,
    year:Option<String>,
    country:Option<String>,
    cast:Option<String>,
    genre:Option<String>,
    synopsis:Option<String>,
}


impl Section_info {
    fn read(&self, info_src: &String) {
        let filename = info_src;
        //println!("file name info: {}", &filename);
        let reader = fs::read_to_string(filename)
                                .expect("Except: file info.txt does not exist");
        let mut lines = reader.lines();
        //println!("CONTENTS info: {:?}", &lines);
            
        for line in lines {
            if line.contains("Original title") {
                //original_title = find(&reader, &line).unwrap().trim();
                self.original_title = Some(find(&reader, &line).unwrap().trim().to_string());
            } else if line.contains("Year") {
                self.year = Some(find(&reader, &line).unwrap().trim().to_string());
            } else if line.contains("Country") {
                self.country = Some(find(&reader, &line).unwrap().trim().to_string());
            } else if line.contains("Synopsis") {
                self.synopsis = Some(find(&reader, &line).unwrap().trim().to_string());
            } else if line.contains("Cast") {
                self.cast = Some(find(&reader, &line).unwrap().trim().to_string());
            } else if line.contains("Genre") {
                self.genre = Some(find(&reader, &line).unwrap().trim().to_string());
            }

        } // end for line
    

    } // end fn read
    
    fn show(&self) {
        println!("Original title is: {}", self.original_title.unwrap());
        println!("Year is: {}", self.year.unwrap());
        println!("Country is: {}", self.country.unwrap());
        
    } // end fn show
}

How about splitting reading the file and constructing your struct into two methods?

#[derive(Default)]
struct SectionInfo {
    original_title: Option<String>,
    year: Option<String>,
    country: Option<String>,
    cast: Option<String>,
    genre: Option<String>,
    synopsis: Option<String>,
}

impl SectionInfo {
    fn from_file(filename: &str) -> Self {
        let reader = fs::read_to_string(filename).expect("Except: file does not exist");

        Self::from_str(&reader)
    }

    fn from_str(reader: &str) -> Self {
        let mut res = Self::default();

        for line in reader.lines() {
            if line.contains("Original Title") {
                //original_title = find(&reader, &line).unwrap().trim();
                res.original_title = Some(find(&reader, &line).unwrap().trim().to_string());
            } else if line.contains("Year") {
                res.year = Some(find(&reader, &line).unwrap().trim().to_string());
            } else if line.contains("Country") {
                res.country = Some(find(&reader, &line).unwrap().trim().to_string());
            } else if line.contains("Synopsis") {
                res.synopsis = Some(find(&reader, &line).unwrap().trim().to_string());
            } else if line.contains("Cast") {
                res.cast = Some(find(&reader, &line).unwrap().trim().to_string());
            } else if line.contains("Genre") {
                res.genre = Some(find(&reader, &line).unwrap().trim().to_string());
            }
        }

        res
    }
}

As to your find function and how you use it, we've talked about it before.

2 Likes

How i supposed instanciate ?
let mut movie = SectionInfo::read(filename); ??

I would implement the FromStr trait (for instancing from a Str) and Display trait (for 'show/printing'). The from_file function would call SectionInfo::from_str.
You can even go further and implement From<&Path> which will replace the from_file function.

1 Like

i need obtain a certain data. like this:
println!("Original title is: {}", SectionInfo.original_title.unwrap());

nothing above will block you from doing that, by default the original_title is gonna be private and cannot be accessed from other modules, depends on your usage/design you can either add pub to it or create a helper function.

To read a info.txt
Sorry me. how pass this piece to struct, to reuse in other object types, by example in books, news letter, etc. ??

use std::{fs};

// return a found field
fn find<'a>(input: &'a str, key: &str) -> Option<&'a str> {
    let mut found: bool = false;
    for line in input.lines() {
        // ... you know you return the line AFTER the line where you found `key`, right?
        if found {
            return Some(line);
        } else if line.contains(key) {
            found = true;
        }
    }
    None
}

fn main() {
    let filename = "/home/pichibw/movie/info.txt";
    //println!("file name info: {}", &filename);
    let reader = fs::read_to_string(filename)
            .expect("Except: info.txt not exist");
    
    let mut lines = reader.lines();    
    
    let mut original_title = "";
    let mut year = "";
    
    for line in lines {
        if line.contains("Original title") {
            original_title = find(&reader, &line).unwrap().trim();                
        } else if line.contains("Year") {
            year = find(&reader, &line).unwrap().trim();
        }
    }
    
    println!("Original title is -> {}", &original_title);
    println!("Original year is -> {}", &year);
    
}

NOTE: info.txt contains:
Original title
The Good man
Year
2000

Help, this give me error:
error[E0107]: this type alias takes 1 generic argument but 2 generic arguments were supplied
--> src/main.rs:14:46
|
14 | let lines = reader.lines().collect::<Result<,>>()?;
| ^^^^^^ - help: remove this generic argument
| |
| expected 1 generic argument

use std::fs::File;
use std::io::{BufRead, BufReader, Result};

struct TextFile {
    lines: Vec<String>,
}

impl TextFile {
    fn new(filename: &str) -> Result<TextFile> {
        let file = File::open(filename)?;
        let reader = BufReader::new(file);
        let lines = reader.lines().collect::<Result<_,_>>()?;
        
        Ok(TextFile {lines})
    }
    
    fn print_lines(&self) {
        for line in &self.lines {
            println!("{}", line);
        }
    }
}


fn main() {
   let text_file = TextFile::new("/home/pichi/info.txt");
   match text_file {    
    Ok(file) => file.print_lines(),
    Err(err) => println!("error {}", err),
   }
}

Following the suggestion:

-        let lines = reader.lines().collect::<Result<_,_>>()?;
+        let lines = reader.lines().collect::<Result<_>>()?;

And the reason is that you have imported std::io::Result, which is an alias for a Result where the error variant is hardcoded to std::io::Error. Because the second parameter (the error variant) is hardcoded, the alias only has one type parameter.

Alternatively you could import std::io [1] and use io::Result where it is expected, and Result will still be the std::result::Result that you're use to.


  1. aka std::io::self ↩︎

2 Likes