String field default

This code:

fn main() {}

#[derive(Default)]
pub struct Structer {
    #[default]
    pub stringy: String,
}

Produces this error:

the `#[default]` attribute may only be used on unit enum variants
consider a manual implementation of `Default`rustcClick for full compiler diagnostic
core::default
derive_helper default

I think it should be possible to use field string default like I did. Just set it to an empty string value like you would when doing String::default()

You may use URLO to ask such questions.

In case you want an empty string, #[derive(Default)] is enough:

#[derive(Default)]
pub struct Structer {
    pub stringy: String,
}

You could use Default::default() to create a Structer after Default is derived:

fn main() {
    let a:Structer=Default::default();
    let b = Structer{..Default::default()};
    let c = Structer{stringy: Default::default()};
}

All the methods is OK to generate a Structer

2 Likes

Ok, I just wanted to make sure I didn't request too much at once. If the above feature is already implemented then here is the thing I actually wanted to do:

my code:

fn main() {}

#[derive(Default)]
pub struct Structer {
    #[default("ok")]
    pub stringy: String,
}

produces this error:

the `#[default]` attribute may only be used on unit enum variants
consider a manual implementation of `Default`rustcClick for full compiler diagnostic

Can u implement this feature?

I think it shouldn't be that hard to impl it. I imagine it would go something like this:

  1. read the token inserted in the default attribute (in this case "ok")
  2. check the type of the token (in this case &str)
  3. check the required type of the field
  4. append ".to_string() to the token
  5. use the modified token as field value like this:
fn default(modified_token: &str) -> String {
    let default = Structer {
        stringy: modified_token.to_string()
    };
    default
}

I tried the derivative crate but it doesn't seem to support string values, only integers etc

Currently, since the variadic parameter is not supported yet, we cannot impl a function that accept different parameter without some hacks.

The best choice is that

pub struct Structer {
    pub stringy: String,
}
// method 1, define the custom default function, then Default::default for Structer will generate stringy with "ok" as default.
impl Default for Structer {
    fn default()->Self {Self{stringy:"ok".to_string()}}
}
// method 2, impl a new default function, you could then call Structer::new to generate your default struct
impl Structer {
    fn new()->Self {Self{stringy:"ok".to_string()}}
}

Years ago I wrote a crate that provides just that.

3 Likes

This is not a thing that derives are allowed to do. All the derive sees is the literal tokens that make up the type definition. So if it sees String, that could be any type, even &'static str. Or the type could be Foo, and that's sometimes a type alias for String.

It's awkward since it requires writing Rust code in a string literal, but it does support arbitrary expressions, e.g.

#[derivative(Default(value="\"ok\".into()"))]

More directly applicable to your usage is smart_default, which allows writing:

#[default("ok".into())]
5 Likes

It's worth noting that this requirement also applies to built-in derives as they are currently implemented, not just user-written derives.

wow that's an awesome crate! thanks!