[英]How can I implement Default for &Struct?
After reading the rust book many times I think I'm starting to get the gist of lifetimes, but for me, an additional problem is the syntax we need to use to declare them.在多次阅读 rust 书后,我想我开始了解生命周期的要点,但对我来说,另一个问题是我们需要使用声明它们的语法。 I find it is really counterintuitive.我觉得这真的违反直觉。
I've simplified a silly code of mine onto this pair of structs (which one referencing the other).我已经将我的一个愚蠢的代码简化到这对结构上(其中一个引用另一个)。
#[derive(Debug, Default)]
pub struct TestStructA {
pub byte_1: u8,
pub byte_2: u8,
pub vector: Vec<u8>,
}
impl<'a> Default for &'a TestStructA {
fn default() -> &'a TestStructA {
&TestStructA { byte_1: 10, byte_2: 20, vector: 'a vec![1, 2, 3] }
}
}
#[derive(Debug, Default)]
pub struct TestStructB<'a> {
pub test_array: &'a [u8],
pub t_a: &'a TestStructA,
}
If you copy and paste this isolated code onto a main.rs file and compile it, then you get the following error:如果您将此隔离代码复制并粘贴到 main.rs 文件并进行编译,则会收到以下错误:
error: expected `while`, `for`, `loop` or `{` after a label
--> src/main.rs:10:59
|
10 | &TestStructA { byte_1: 10, byte_2: 20, vector: 'a vec![1, 2, 3] }
| ^^^ expected `while`, `for`, `loop` or `{` after a label
error: labeled expression must be followed by `:`
--> src/main.rs:10:59
|
10 | &TestStructA { byte_1: 10, byte_2: 20, vector: 'a vec![1, 2, 3] }
| ---^^^^^^^^^^^^^
| | |
| | help: add `:` after the label
| the label
|
= note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
If I don't annotate the vector parameter lifetime, I get the expected: "check your lifetimes boy" (which makes sense).如果我不注释向量参数生命周期,我会得到预期的:“检查你的生命周期男孩”(这是有道理的)。
error[E0515]: cannot return reference to temporary value
--> src/main.rs:10:9
|
10 | &TestStructA { byte_1: 10, byte_2: 20, vector: vec![1, 2, 3] }
| ^-------------------------------------------------------------
| ||
| |temporary value created here
| returns a reference to data owned by the current function
Of course, if I choose a more drastic solution as removing the "vector" attribute from my struct, as all other attributes are scalars, the code compiles.当然,如果我选择一个更激进的解决方案作为从我的结构中删除“向量”属性,因为所有其他属性都是标量,代码编译。 But I need my struct to have non-scalar data structures of some kind.但是我需要我的结构具有某种非标量数据结构。 I suspect I need some kind of lifetime labeling for my vector inside the Default initializer, but I'm not sure what我怀疑我需要在默认初始化程序中为我的向量添加某种生命周期标签,但我不确定是什么
By the way, I think my TestStructB
is also properly lifetime annotated, but maybe not.顺便说一句,我认为我的TestStructB
也有适当的生命周期注释,但也许没有。 Does it look correct?它看起来正确吗?
Finally, I got here because the compiler said I needed to declare a Default initializer for the referenced (&) version of my original struct.最后,我来到这里是因为编译器说我需要为原始结构的引用 (&) 版本声明一个默认初始化程序。 This original struct was already happily used in my program, but never referenced.这个原始结构已经在我的程序中愉快地使用了,但从未被引用过。 Whenever I started using it in a &referenced fashion, it was Rust claiming it needs its Default initializer.每当我开始以 &referenced 方式使用它时,它就是 Rust 声称它需要它的默认初始化程序。 The thing is I still somewhat think I've done something wrong when using my referenced Struct, and that there is a proper way to use &referenced (and lifetime annotated) Structs without Rust complaining about their (non existing) default initializer.问题是我仍然觉得在使用引用的 Struct 时我做错了什么,并且有一种正确的方法可以使用 &referenced(和生命周期注释)的 Struct,而 Rust 不会抱怨他们的(不存在的)默认初始化程序。
EDIT: @JohnKugelman is more than right, I've come onto this "aberration" after the typical newbie fight with rust compiler trying to overcome the mainly cryptic messages it yields.编辑:@JohnKugelman 是正确的,在与 rust 编译器试图克服它产生的主要神秘消息进行典型的新手战斗之后,我遇到了这种“异常”。
My simplified original was this one:我的简化原件是这个:
#[derive(Debug, Default)]
pub struct TestStructA {
pub byte_1: u8,
pub byte_2: u8,
pub vector: Vec<u8>,
}
#[derive(Debug, Default)]
pub struct TestStructB<'a> {
pub test_array: &'a [u8],
pub t_a: &'a TestStructA,
}
With this code, the error I get is:使用此代码,我得到的错误是:
error[E0277]: the trait bound `&TestStructA: Default` is not satisfied
--> src/main.rs:11:5
|
11 | pub t_a: &'a TestStructA,
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `&TestStructA`
|
= help: the following implementations were found:
<TestStructA as Default>
= note: required by `std::default::Default::default`
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
Apparently rustc misled me into thinking I need a &Struct
Default initializer?显然 rustc 误导我认为我需要一个&Struct
Default 初始化程序? Can't say...不能说...
Your unusual requirement arises because you're trying to implement Default
for a structure TestStructB
containing a reference.出现您不寻常的要求是因为您尝试为包含引用的结构TestStructB
实现Default
。 Most of the time, Default
is used on types that have all owned values or can be empty in some way.大多数时候, Default
用于具有所有拥有值或可以以某种方式为空的类型。
In order to implement Default
for a reference &'a TestStructA
, you would have to have some constant or leaked value of the type that the Default::default
implementation can return a reference to — basically there needs to be an &'static TestStructA
.为了实现引用&'a TestStructA
Default
您必须有一些Default::default
实现可以返回引用的类型的常量或泄漏值——基本上需要有一个&'static TestStructA
。
This is simple to do if the vector is empty because Vec::new()
is a const fn
, so we can construct a full compile-time-constant instance of TestStructA
:如果向量为空,这很简单,因为Vec::new()
是一个const fn
,所以我们可以构造一个完整的编译时常量TestStructA
实例:
impl<'a> Default for &'a TestStructA {
fn default() -> &'a TestStructA {
static VALUE: TestStructA = TestStructA {
byte_1: 10,
byte_2: 20,
vector: Vec::new()
};
&VALUE
}
}
If you want to have some data in the vector, then you would have to use a lazy-initialization mechanism likeonce_cell
to be able to execute vec!
如果你想在向量中有一些数据,那么你必须使用像once_cell
这样的惰性初始化机制才能执行vec!
to allocate the vector's contents, then return a reference to it.分配向量的内容,然后返回对它的引用。
use once_cell::sync::Lazy;
static DEFAULT_A: Lazy<TestStructA> = Lazy::new(|| {
TestStructA {byte_1: 10, byte_2: 20, vector: vec![1, 2, 3]}
});
impl<'a> Default for &'a TestStructA {
fn default() -> &'a TestStructA {
&DEFAULT_A
}
}
If you were to do this, I'd recommend also implementing Default for TestStructA
, because it is strange to have Default
for the reference but not the owned value.如果您要这样做,我建议您还Default for TestStructA
,因为将Default
作为引用而不是拥有值是很奇怪的。
impl Default for TestStructA {
fn default() -> TestStructA {
DEFAULT_A.clone()
}
}
(This only works if TestStructA
also implements Clone
, but it probably should. If it shouldn't, then instead put the struct literal inside the TestStructA::default
method and have DEFAULT_A
just be defined as Lazy::new(TestStructA::default)
.) (这仅在TestStructA
也实现Clone
时才有效,但它可能应该。如果不应该,则将结构文字放在TestStructA::default
方法中,并将DEFAULT_A
定义为Lazy::new(TestStructA::default)
.)
However, all these details are only necessary because然而,所有这些细节都是必要的,因为
Default
for TestStructB
,您正在为TestStructB
实现Default
,TestStructA
.它始终包含对TestStructA
的引用。 You should consider whether TestStructB
actually needs this reference in the default case — if t_a
has type Option<&'a TestStructA>
, for example, then it can just default to None
.您应该考虑TestStructB
在默认情况下是否真的需要这个引用——例如,如果t_a
的类型Option<&'a TestStructA>
,那么它可以默认为None
。 I don't have enough information to say whether this is appropriate for your application — make your own choice based on what the exact purpose of these structures is.我没有足够的信息来说明这是否适合您的应用程序 - 根据这些结构的确切用途做出您自己的选择。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.