String compare in Some failing

I can't seem to figure out how to string compare a value defined in some.

....
Some(data) => {
   if data == "duration" {
        ....
   }
}

data comes in as a &String
no matter how I try and compare the data with "duration" it always fails.

I have tried using eq instead of ==.
I have tried converting it to a &str first and them compare it with == and eq
I have tried comparing it with a String::from("duration")

String comparison should be a easy task and yet even though the data value is "duration" and I compare it with another string of the same value it just keeps returning false.

Having said that, if I manually do that in a text function it returns true.
Is there something in the option causing this to fail?

What is the actual type of data? Is it &String or &&String? You can verify by doing this:

let a: u32 = data;

and reading the compiler error.

Anyway, try using data.as_str() == "duration" and see if that helps.

If it compiles but the result is false, then the contents of data is not `"duration".

Did you verify what it actually is, by printing it? Or does it contain invisible/un-printable characters by any chance? A common beginner mistake is reading a line from a file and then forgetting that the last character is a newline \n character.

1 Like

Ah, I thought that it was failing to compile. If it's compiling but returning false, then that's another matter.

Can you provide a reproducible case in the playground? Here's an example that clearly works based on the information that you have provided.

1 Like

Are you getting the input from stdin? If so, you'll need to trim it before comparing, because it will contain a trailing newline.

1 Like

To add to @H2CO3's suggestion of printing the string, if you print the Debug flavor of the string, it will show you invisible characters: Rust Playground

4 Likes

I am going to try and reconstruct this on the playground and I will also still try try the H2CO3.
But just as a quick reference so long

let is_duration = data_type == "duration";
println!("{} is 'duration': {}", data_type, is_duration);

result

"duration" is 'duration': false
let is_duration = data_type.as_str() == "duration";
println!("{} is 'duration': {}", data_type, is_duration);

result

"duration" is 'duration': false

I suspect I am doing something stupid with the borrowing, will try and reconstruct it on sandbox and link it here.

As others noted, use the Debug printing, that is, with the pattern {:?} instead of {}! In this case it seems as if the string might be containing quotes; try to see if it's equal to "\"duration\"".

1 Like

Playground example

the debug indicates that there are double quotes in the string thus the value is

"\"duration\""

Just not sure how to declare the value in Value::from so that it does not have the quotes.

Yep, as I said:

[src/main.rs:28] &data_type = "\"duration\""

(playground)

That's great but how do I get the value without the quotes in the value?

Apparently, serde_json's Value type has a Display implementation that produces JSON syntax. Then, to_string method in Rust always uses the Display implementation. Of course, JSON syntax has the quotes. The Value type is an enum though, so you can match in that, or use the as_str method and match against the returned Option<&str>.

Edit: In this case, you'll have to think about what to do when the JSON is more complex than just a string value.

You shouldn't call to_string() on a Value unless you want the JSON-serialized string. Just think about it, if the ToString impl for Value didn't produce valid JSON (including the act of surrounding strings with quotes), then how would one be able to differentiate between the string null and the literal JSON null value?

Since a JSON value is not necessarily a string (dynamic typing is the whole point of the existence of Value!), you will have to explicitly extract a string from it and handle the case where it doesn't contain one.

The easiest way to "handle" the non-String case is to simply ignore it and yield None, which is demonstated here:

impl Field {
    pub fn new(name: String, data_type: Option<&Value>) -> Field {
        let data_type = data_type.and_then(Value::as_str).map(str::to_owned);

        Field {
            name,
            data_type
        }
    }
}
5 Likes

Since I am new to all this it seems there are some under the hood stuff I am not yet familiar with that I will need to go study up on.

Thank you for all your help on helping me understand this issue.

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.