7

I am attempting to write a lexer for fun, however something keeps bothering me.

let mut chars: Vec<char> = Vec::new();
let mut contents = String::new();
let mut tokens: Vec<&String> = Vec::new();
let mut append = String::new();
//--snip--
for _char in chars {
    append += &_char.to_string();
    append = append.trim().to_string();

    if append.contains("print") {
        println!("print found at: \n{}", append);
        append = "".to_string();
    }
}

Any time I want to do something as simple as append a &str to a String I have to convert it using .to_string, String::from(), .to_owned, etc.

Is there something I am doing wrong, so that I don't have to constantly do this, or is this the primary way of appending?

trent
  • 25,033
  • 7
  • 51
  • 90

2 Answers2

10

If you're trying to do something with a type, check the documentation. From the documentation for String:

  • push: "Appends the given char to the end of this String."
  • push_str: "Appends a given string slice onto the end of this String."
DK.
  • 55,277
  • 5
  • 189
  • 162
3

It's important to understand the differences between String and &str, and why different methods accept and return each of them.

A &str or &mut str are usually preferred in function arguments and return types. That's because they are just pointers to data so nothing needs to be copied or moved when they are passed around.

A String is returned when a function needs to do some new allocation, while &str and &mut str are slices into an existing String. Even though &mut str is mutable, you can't mutate it in a way that increases its length because that would require additional allocation.

The trim function is able to return a &str slice because that doesn't involve mutating the original string - a trimmed string is just a substring, which a slice perfectly describes. But sometimes that isn't possible; for example, a function that pads a string with an extra character would have to return a String because it would be allocating new memory.


You can reduce the number of type conversions in your code by choosing different methods:

for c in chars {
    append.push(c); // append += &_char.to_string();
    append = append.trim().to_string();

    if append.contains("print") {
        println!("print found at: \n{}", append);
        append.clear(); // append = "".to_string();
    }
}

There isn't anything like a trim_in_place method for String, so the way you have done it is probably the only way.

Peter Hall
  • 53,120
  • 14
  • 139
  • 204