簡體   English   中英

更新具有私有字段的Rust結構的公共字段

[英]Updating public fields of Rust structs which have private fields

我有一個結構Foo ,代表一個外部序列化格式。 Foo有幾十個領域,而且還有更多領域。 令人高興的是,所有新領域都保證有合理的默認值。

Rust有一個很好的語法,可以使用默認值創建結構,然后更新一些選定的值:

Foo {
  bar: true,
  ..Default::default()
} 

類似地,我們可以使用PhantomData類型的私有字段來表示“此結構在未來版本中可能包含更多字段”的PhantomData

但如果我們將這兩個習語結合起來,就會出現錯誤:

use std::default::Default;

mod F {
    use std::default::Default;
    use std::marker::PhantomData;

    pub struct Foo {
        pub bar: bool,
        phantom: PhantomData<()>,
    }

    impl Default for Foo {
        fn default() -> Foo {
            Foo {
                bar: false,
                phantom: PhantomData,
            }
        }
    }
}

fn main() {
    F::Foo {
        bar: true,
        ..Default::default()
    };
}

這給了我們錯誤:

error: field `phantom` of struct `F::Foo` is private [--explain E0451]
  --> <anon>:23:5
   |>
23 |>     F::Foo {
   |>     ^

從邏輯上講,我認為這應該有效,因為我們只是更新公共字段,這將是有用的習慣用法。 另一種方法是支持以下內容:

Foo::new()
  .set_bar(true)

......幾十個領域都會變得單調乏味。

我該如何解決這個問題?

默認字段語法不起作用,因為您仍在創建新實例(即使您嘗試從另一個對象獲取某些字段值)。

另一種方法是支持以下內容:

 Foo::new() .set_bar(true) 

......幾十個領域都會變得單調乏味。

我不確定即使有很多領域,這個:

Foo::new()
   .set_bar(true)
   .set_foo(17)
   .set_splat("Boing")

比以下更加繁瑣:

Foo {
   bar: true,
   foo: 17,
   splat: "Boing",
   ..Foo::default()
}

或者,您可以將公共字段分離為自己的類型:

pub struct FooPub {
    pub bar: bool,
    // other pub fields
}

pub struct Foo {
    pub bar: bool,
    // other pub fields
    // alternatively, group them: pub public: FooPub,

    foo: u64,
}

impl Foo {
    pub fn new(init: FooPub) {
        Foo {
            bar: init.bar,
            // other pub fields
            // alternative: public: init

            // private fields
            foo: 17u64,
        }
    }
}

然后你將它稱為:

Foo::new(FooPub{ bar: true })

或者添加一個fn FooPub::default()來默認一些字段:

Foo::new(FooPub{ bar: true, ..FooPub::default()})

phantom重命名為__phantom ,將其公開並#[doc(hidden)]

use std::default::Default;

mod foo {
    use std::default::Default;
    use std::marker::PhantomData;

    pub struct Foo {
        pub bar: bool,

        // We make this public but hide it from the docs, making
        // it private by convention.  If you use this, your
        // program may break even when semver otherwise says it
        // shouldn't.
        #[doc(hidden)]
        pub _phantom: PhantomData<()>,
    }

    impl Default for Foo {
        fn default() -> Foo {
            Foo {
                bar: false,
                _phantom: PhantomData,
            }
        }
    }
}

fn main() {
    foo::Foo {
        bar: true,
        ..Default::default()
    };
}

這是一個不太常見的模式,實例: std::io::ErrorKind::__Nonexhaustive

當然,如果用戶選擇使用__named字段,用戶將不會有任何警告或任何內容,但是__使得意圖非常明確。 如果需要警告,可以使用#[deprecated]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM