Translate

2021-04-06

Learning Rust. Part 9. Training project, editor. Making String possible to Copy



It's perhaps useful to read one *short* and outstandingly clear article on strings, slices and string literals: 
https://blog.thoughtram.io/string-vs-str-in-rust/
Highly recommended. That article should be a part of the rust documentation!
When I say "Let's run it" below, remember that what I'm running is the whole program code

OK, back on track. In the last blog post it was time to write the results from the comment_start() function. Here I was bound to get in trouble, my PHP experience tricking me into un-Rustable behavior. Here the statements for opening and writing to the file are added. Lets run it (results below the code):

 fn comment_start(fname_ini:String) {

    let mut s = String::new();
    let a:&str = "1";
    let b:&str = "1";
    while a == "1" && b == "1" {
        s = t_get(s);
        let n1 = s.len()-1;
        let ch1 = s.chars().nth(n1).unwrap();
        print!("{}",ch1);
        io::stdout().flush().unwrap();

        s=t_get(s);
        let n2 = s.len()-1;
        let ch2 = s.chars().nth(n2).unwrap();
        print!("{}",ch2);
        io::stdout().flush().unwrap();
        if (ch1 == '*') && (ch2 == '/') {
            print!("\n\n{}",s);
            let f = open_file( fname_ini);
            write_file(s, f);

        list(fname_ini);
        io::stdout().flush().unwrap();
        exit(0);
        }

        if ch2 == '*' {
            s=t_get(s);
            let n3 = s.len()-1;
            let ch3 = s.chars().nth(n3).unwrap();
            print!("{}",ch3);
            io::stdout().flush().unwrap();
            if ch3 == '/' { 
            let f = open_file(fname_ini);
            write_file(s, f);

            list(fname_ini);
            exit(0);
            }
        }
    }
}

 cargo run                                                           
  Compiling playground v0.1.0 (/home/snkdb/rust/projects/playground)

error[E0382]: use of moved value: `fname_ini`                                                                         
  --> src/main.rs:182:14                                                                                             
   |                                                                                                                 
160 |  fn comment_start(fname_ini:String) {                                                                           
   |                   --------- move occurs because `fname_ini` has type `std::string::String`, which does not impl
ement the `Copy` trait
...
180 |             let f = open_file( fname_ini);
   |                                --------- value moved here
181 |             write_file(s,f);
182 |         list(fname_ini);
   |              ^^^^^^^^^ value used here after move


error[E0382]: use of moved value: `fname_ini`
  --> src/main.rs:196:18
   |
160 |  fn comment_start(fname_ini:String) {
   |                   --------- move occurs because `fname_ini` has type `std::string::String`, which does not impl
ement the `Copy` trait
...
194 |             let mut f = open_file(fname_ini);
   |                                   --------- value moved here
195 |             write_file(s,f);
196 |             list(fname_ini);
   |                  ^^^^^^^^^ value used here after move

error: aborting due to 2 previous errors; 4 warnings emitted

Ouch! Twice I've moved the filename and then tried to use it afterwards, which should, in Rust, force a "Copy" that "String" doesn't support. The first spasm of trying to solve it is to NOT move, just "borrow" it. Lets point to the value instead of copying it. Lets change let f = open_file( fname_ini); to
let f = open_file( &fname_ini); and run again.

Ooops! Surprisingly ( :) there was a new error:

error[E0308]: mismatched types
  --> src/main.rs:180:32
   |
180 |             let f = open_file( &fname_ini);
   |                                ^^^^^^^^^^
   |                                |
   |                                expected struct `std::string::String`, found `&std::string::String`
   |                                help: consider removing the borrow: `fname_ini`

error: aborting due to previous error

...and that is just the beginning of a hopeless twiddling of parameters and pointers and what not, until you realize you have to go all the way to the bottom of it.
I have to remake the fname_ini into something that CAN be copied around.

"str" (or rather "&str") is a String-like thing (it contains letters, that's where the similarity ends) that may be copied. 
Let's add let fname_slice: &str = &fname_ini; on the line below the function name:
 fn comment_start(fname_ini:String) {
    let fname_slice: &str = &fname_ini;  . . .

and then change the let f = open_file( &fname_ini); to let f = open_file( fname_slice); and run cargo again. 

Result:
error[E0308]: mismatched types
  --> src/main.rs:180:31
   |
180 |             let f = open_file(fname_slice);
   |                               ^^^^^^^^^^^
   |                               |
   |                               expected struct `std::string::String`, found `&str`
   |                               help: try using a conversion method: `fname_slice.to_string()`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground`.

Oopsiedoopsie! Well, that's understandable since write_file() needs "String" as an argument. For once, let's do as he says: let f = open_file( &fname_ini); to let f => open_file( fname_slice.to_string());
not forgetting to put "()" at the end of ".to_string(). Then I try once more:

Result:
error[E0382]: use of moved value: `fname_ini`
  --> src/main.rs:196:18
   |
160 |  fn comment_start(fname_ini:String) {
   |                   --------- move occurs because `fname_ini` has type `std::string::String`, which does not impl
ement the `Copy` trait
...
194 |             let mut f = open_file(fname_ini);
   |                                   --------- value moved here
195 |             write_file(s,f);
196 |             list(fname_ini);
   |                  ^^^^^^^^^ value used here after move

error: aborting due to previous error; 4 warnings emitted

Now look at that! It's says nothing about line 180. Instead it has passed on to another irregularity of the same kind but farther down in the code. That's good. Let's make these changes in all places where I use the "fname_ini"... Done!

cargo run                                                 [25/1814]
  Compiling playground v0.1.0 (/home/snkdb/rust/projects/playground)
   Finished dev [unoptimized + debuginfo] target(s) in 0.62s
    Running `/home/snkdb/rust/projects/playground/target/debug/playground`

[[=header|[=item|/*=start comment|*/=end comment|l=list file
Enter something:

YAY! It worked! The corrected code now looks like the one below. 
Let's run it and enter a comment, I'd like to see that it works i real life. Results will appear below the code.

 fn comment_start(fname_ini:String) {
    let fname_slice: &str = &fname_ini;
    let mut s = String::new();
    let a:&str = "1";
    let b:&str = "1";

    while a == "1" && b == "1" {
        s = t_get(s);
        let n1 = s.len()-1;
        let ch1 = s.chars().nth(n1).unwrap();
        print!("{}",ch1);
        io::stdout().flush().unwrap();

        s=t_get(s);
        let n2 = s.len()-1;
        let ch2 = s.chars().nth(n2).unwrap();
        print!("{}",ch2);
        io::stdout().flush().unwrap();
        if (ch1 == '*') && (ch2 == '/') {
            print!("\n\n{}",s);                                        // this one should be deleted! (Forgot)
            let f = open_file(fname_slice.to_string());
            write_file(s,f);
        list(fname_slice.to_string());
        io::stdout().flush().unwrap();
        exit(0);
        }
        
        if ch2 == '*' {
            s=t_get(s);
            let n3 = s.len()-1;
            let ch3 = s.chars().nth(n3).unwrap();
            print!("{}",ch3);
            io::stdout().flush().unwrap();
            if ch3 == '/' { 
            let f = open_file(fname_slice.to_string());
            write_file(s,f);
            list(fname_slice.to_string());
            
            exit(0);
            }
        }
    }
}

Results:
 cargo run                                                           
  Compiling playground v0.1.0 (/home/snkdb/rust/projects/playground)
    Finished dev [unoptimized + debuginfo] target(s) in 0.62s
    Running `/home/snkdb/rust/projects/playground/target/debug/playground`

[[=header|[=item|/*=start comment|*/=end comment|l=list file
Enter something: /*    // command for "start commenting"
This is a comment
And this is another one
*/                      // command ending the comment

This is a comment       //this is an unnecessary printout of the result (three lines)
And this is another one // it's the print!("\n\n{}",s); I forgot to delete! Arggh!
*/__________            // The real listing starts here w. an empty line directly after "*/"
1 [testing1]
2 item1: some
3  
4 [testing2]
5 item2: other
6  
7 This is a comment
8 And this is another one
9 */            // ... and this one shouldn't be included. I'll have to fix that!

OK, that felt good. The next thing is to add a function for adding the comment at a certain position, using the line number from the list() function (and adjust some stupidities in this printout). Ah, one more: I need some inline editing when writing comments! There's also so much more to learn...

To be continued...


Inga kommentarer:

Skicka en kommentar