Printing `Option` without the `Some` wrapper

How can I print Option<String> such that None prints as None while Some("abc") prints as just "abc" rather than Some("abc"). This is to make the output more readable.

I implemented a workaround that creates a separate variable for the thing I wanna debug. This separate variable takes the original variable and iterates through all its elements and does .unwrap_or("None".to_string()). So the debug output looks good now. But I think this still has the problem of making the code messy. Is there a cleaner way to achieve a clean print output?

2 Likes
fn print_option<T>(x: Option<T>)
where
    T: std::fmt::Debug,
{
    if let Some(x) = x {
        println!("{x:?}");
    } else {
        println!("None");
    }
}

You can add a layer of reference. I'd advise you keep the Some wrapper in your output anyway, since you're using the debug representation of Option. Keep it coherent and simple.

3 Likes

I don't think this is that much cleaner compared to the impl I wrote about. I guess this is something that Rust needs to add intrinsically to the language design. Perhaps of similar nature as {:?} but perhaps some other symbol.

I need the Some wrapper removed because the output will be read by people who aren't familiar with Rust, and they might think that the Some wrapper is part of the value and they might get confused.

Then you'd be better served by using an actual serializer or writing a Display implementation for your struct that contains the Option.

8 Likes

This is not the usecase of Debug but rather Display. You will need to write your own implementation (or use a crate).

13 Likes

do u know the name of any such crate?

e.g. derive_more·

Edit: Actually, while this one simplifies Display implementations for many use-cases, it seems like special handling of different enum variants of an existing enum (Option) in a field is not something it can help much with.

2 Likes

Which means, of course, that Some("None") and None will print identically.

3 Likes

None(Other(Than(Some(None))))

Not quite, these would be displayed as "None" and None (note the lack of delimiters) if I'm understanding correctly.

It's still fragile though if used with types other than String. I'm not sure how I'd expect an Option<Option<T>> to be formatted to distinguish between None and Some(None).

2 Likes

Try show-option crate:

println!("received bytes: {}", optional_value.show_or("None"));

This doesn't really solve the printing Container<Option<T>> problem, which is what OP want to solve.

I see nothing about container in the original post.

However, here is how to print container of Option:

#!/usr/bin/env run-cargo-script

//! ```cargo
//! [package]
//! edition = "2021"
//! [dependencies]
//! show-option = "*"
//! itertools = "*"
//! ```

use show_option::prelude::*;
use itertools::Itertools as _;

fn main() {
    let data = vec![Some(20), None, Some(10)];
    println!("{}", data.iter().map(|v| v.show_or("None")).format(", "));
}

Result: 20, None, 10

Ah, yes, right, if we use {:?}, it also prints quotation marks.

This seems to have similar verbosity level as v.unwrap_or("None)

It only works if v is str, show_option works for any Displayable without prior conversion to string.

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.