在Rust结构体中,有更快/更简短的初始化变量的方法吗?

209
在下面的例子中,我更喜欢在结构的字段声明中为每个字段分配一个值。或者说,为了给字段赋值,每个字段需要增加一个额外的语句。我想要的是在结构体被实例化时能够分配默认值。
有没有更简洁的方法来做到这一点?
struct cParams {
    iInsertMax: i64,
    iUpdateMax: i64,
    iDeleteMax: i64,
    iInstanceMax: i64,
    tFirstInstance: bool,
    tCreateTables: bool,
    tContinue: bool,
}

impl cParams {
    fn new() -> cParams {
        cParams {
            iInsertMax: -1,
            iUpdateMax: -1,
            iDeleteMax: -1,
            iInstanceMax: -1,
            tFirstInstance: false,
            tCreateTables: false,
            tContinue: false,
        }
    }
}
2个回答

299

通过实现Default特质,您可以为结构体提供默认值。 default 函数看起来像您当前的 new 函数:

impl Default for cParams {
    fn default() -> cParams {
        cParams {
            iInsertMax: -1,
            iUpdateMax: -1,
            iDeleteMax: -1,
            iInstanceMax: -1,
            tFirstInstance: false,
            tCreateTables: false,
            tContinue: false,
        }
    }
}

您可以通过仅提供非默认值来实例化结构体:

let p = cParams { iInsertMax: 10, ..Default::default() };

通过对数据结构进行一些小的更改,您可以利用自动生成的默认实现。如果您在数据结构上使用#[derive(Default)],编译器将自动为您创建一个默认函数,以其默认值填充每个字段。默认布尔值为false,默认整数值为0。

这里整数的默认值为0是一个问题,因为您希望整数字段默认为-1。您可以定义一个实现默认值为-1的新类型,并在结构体中使用它代替i64。(我没有测试过,但应该可以工作)。

然而,我建议稍微改变您的数据结构,使用Option<i64>代替i64。我不知道您代码的上下文,但看起来您正在使用特殊值-1来表示特殊含义“无限”或“没有最大值”。在Rust中,我们使用Option来表示可选存在的值。没有必要使用-1的hack。一个选项可以是NoneSome(x),其中x将是您的i64。如果-1是唯一的负值,甚至可以是无符号整数。默认的Option值是None,因此根据建议的更改,您的代码可能如下所示:

#[derive(Default)]
struct cParams {
    iInsertMax: Option<u64>,
    iUpdateMax: Option<u64>,
    iDeleteMax: Option<u64>,
    iInstanceMax: Option<u64>,
    tFirstInstance: bool,
    tCreateTables: bool,
    tContinue: bool,
}

let p = cParams { iInsertMax: Some(10), ..Default::default() };

2
谢谢,我已经快速阅读了一下,但是我会重新阅读以更好地理解。像零、false、""等某些语言使用的“自然”默认值对我很合适。我确实明白了它比我要解决的小“问题”具有更广泛的影响。能够声明例如“iVal:i64 = 0”将解决我的更广泛需求,但我猜这不会发生。 “#[派生(默认)]”应该满足我大部分的需求。我不确定为什么在我的测试程序中使用了-1,但这并不需要(历史)。在定义字段的地方即时赋值将非常有用(在我看来)。 - Brian Oh
17
@BrianOh,顺带一提,“结构体字段的默认值”(例如 struct Foo { val: i64 = 0 })已经被提出,因此可能会在以后的版本中出现。 - huon
1
要使用所有默认值实例化结构体,请尝试 let p: cParams = Default::default();。无论您自己实现Default特质还是使用#[deriving(Default)]让编译器实现它,在使用方式上都没有区别。 - Zargony
3
非常感谢。在我看来,应该默认采用默认设置。比如说,并不需要指定“Default:default”之类的内容。我认为,应该可以在定义字段时为它们分配一个值。这只是我简单的观点,我知道 Rust 被设计成安全的语言,而且有比我的更广阔的视角。当我们学习这门语言(至少对我来说如此)时,当前的实现似乎有点繁琐。在我看来,Rust 并不是一门简单的语言,因此尽可能地简化它对我来说更好。 - Brian Oh
5
实现结构体的 Default 接口时,是否需要为所有字段定义默认值? - stevensonmt
显示剩余7条评论

40

现在,可以完全实现8年前OP所问的功能。

在字段声明中为结构体的每个字段分配一个值。

使用derivative crate:

#![allow(non_snake_case)]
#![allow(non_camel_case_types)]

use derivative::Derivative;

#[derive(Derivative)]
#[derivative(Debug, Default)]
struct cParams {
    #[derivative(Default(value = "-1"))]
    iInsertMax: i64,
    #[derivative(Default(value = "-1"))]
    iUpdateMax: i64,
    #[derivative(Default(value = "-1"))]
    iDeleteMax: i64,
    #[derivative(Default(value = "-1"))]
    iInstanceMax: i64,
    #[derivative(Default(value = "false"))]
    tFirstInstance: bool,
    #[derivative(Default(value = "false"))]
    tCreateTables: bool,
    #[derivative(Default(value = "false"))]
    tContinue: bool,
}

fn main() {
    println!("cParams: {:?}", cParams::default());
}

同样,不需要以这种方式定义布尔值的默认假值,因为Default将会将它们设置为此值。


19
有一天如果标准库中也能出现类似的东西就太好了。 - at54321
24
希望不是这样,至少不要用这个语法。在我看来,这段代码非常丑陋和冗长。如果必须这样做,那么最好只实现“Default”。没有必要用这些东西来混淆语言,否则很快 Rust 就会变成像 C++ 一样,这将是一个可怕的想法。最好将其保留为一个 crate,如果需要的话人们可以使用它。 - nbro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接