您如何创建部分初始化的结构?
How are you able to create partially initialised structs?
在 Rust 中创建结构时,似乎很难在不设置所有字段的情况下创建结构。例如使用以下代码
struct Connection {
url: String,
stream: TcpStream
}
如果不提供 stream
,则无法设置 url
。
// Compilation error asking for 'stream'
let m = Connection { url: "www.google.com".to_string() };
您如何才能创建这些可能 Option<None>
直到稍后的引用?
我发现的最好的方法是使用 Default
特性,但我宁愿不必创建 TcpStream
直到稍后的时间,而不是在初始化结构时。我可以用 Box
之类的东西来做到这一点吗?
您可以做的一件事是将 TcpStream
包裹在 Option
中,即 Option<TcpStream>
。当您第一次构建结构时,它将是 None
,当您初始化它时,您将其设为 self.stream = Some(<initialize tcp stream>)
。无论你在哪里使用 TCPStream
,你都必须检查它是否是 Some
,即它是否已经被初始化。如果你能保证你的行为,那么你就可以unwrap()
,但最好还是检查一下。
struct Connection {
url: String,
stream: Option<TcpStream>
}
impl Connection {
pub fn new() -> Connection {
Connection {
url: "www.google.com".to_string(),
stream: None,
}
}
pub fn initialize_stream(&mut self) {
self.stream = Some(TcpStream::connect("127.0.0.1:34254").unwrap());
}
pub fn method_that_uses_stream(&self) {
if let Some(ref stream) = self.stream {
// can use the stream here
} else {
println!("the stream hasn't been initialized yet");
}
}
}
如果您熟悉该语言,这与 Swift 中的操作类似。
创建 struct
实例时确实必须初始化所有字段(Rust 中没有 null),因此分配了所有内存。
通常有一个专门的方法(如 new
)为应该在稍后阶段修改的字段设置默认值。
当您不知道字段的大小时(就像 Vec
那样),我会使用 Box
。
作为 的扩展,您可以使用 builder。构建器具有所有可选字段并生成没有 Option
s 的最终值:
use std::net::TcpStream;
struct ConnectionBuilder {
url: String,
stream: Option<TcpStream>,
}
impl ConnectionBuilder {
fn new(url: impl Into<String>) -> Self {
Self {
url: url.into(),
stream: None,
}
}
fn stream(mut self, stream: TcpStream) -> Self {
self.stream = Some(stream);
self
}
fn build(self) -> Connection {
let url = self.url;
let stream = self
.stream
.expect("Perform actual error handling or default value");
Connection { url, stream }
}
}
struct Connection {
url: String,
stream: TcpStream,
}
impl Connection {
fn method_that_uses_stream(&self) {
// can use self.stream here
}
}
这意味着您不必在代码中乱扔乱码来检查流是否已设置。
另请参阅:
- How to write an idiomatic build pattern with chained method calls in Rust?
在 Rust 中创建结构时,似乎很难在不设置所有字段的情况下创建结构。例如使用以下代码
struct Connection {
url: String,
stream: TcpStream
}
如果不提供 stream
,则无法设置 url
。
// Compilation error asking for 'stream'
let m = Connection { url: "www.google.com".to_string() };
您如何才能创建这些可能 Option<None>
直到稍后的引用?
我发现的最好的方法是使用 Default
特性,但我宁愿不必创建 TcpStream
直到稍后的时间,而不是在初始化结构时。我可以用 Box
之类的东西来做到这一点吗?
您可以做的一件事是将 TcpStream
包裹在 Option
中,即 Option<TcpStream>
。当您第一次构建结构时,它将是 None
,当您初始化它时,您将其设为 self.stream = Some(<initialize tcp stream>)
。无论你在哪里使用 TCPStream
,你都必须检查它是否是 Some
,即它是否已经被初始化。如果你能保证你的行为,那么你就可以unwrap()
,但最好还是检查一下。
struct Connection {
url: String,
stream: Option<TcpStream>
}
impl Connection {
pub fn new() -> Connection {
Connection {
url: "www.google.com".to_string(),
stream: None,
}
}
pub fn initialize_stream(&mut self) {
self.stream = Some(TcpStream::connect("127.0.0.1:34254").unwrap());
}
pub fn method_that_uses_stream(&self) {
if let Some(ref stream) = self.stream {
// can use the stream here
} else {
println!("the stream hasn't been initialized yet");
}
}
}
如果您熟悉该语言,这与 Swift 中的操作类似。
创建 struct
实例时确实必须初始化所有字段(Rust 中没有 null),因此分配了所有内存。
通常有一个专门的方法(如 new
)为应该在稍后阶段修改的字段设置默认值。
当您不知道字段的大小时(就像 Vec
那样),我会使用 Box
。
作为 Option
s 的最终值:
use std::net::TcpStream;
struct ConnectionBuilder {
url: String,
stream: Option<TcpStream>,
}
impl ConnectionBuilder {
fn new(url: impl Into<String>) -> Self {
Self {
url: url.into(),
stream: None,
}
}
fn stream(mut self, stream: TcpStream) -> Self {
self.stream = Some(stream);
self
}
fn build(self) -> Connection {
let url = self.url;
let stream = self
.stream
.expect("Perform actual error handling or default value");
Connection { url, stream }
}
}
struct Connection {
url: String,
stream: TcpStream,
}
impl Connection {
fn method_that_uses_stream(&self) {
// can use self.stream here
}
}
这意味着您不必在代码中乱扔乱码来检查流是否已设置。
另请参阅:
- How to write an idiomatic build pattern with chained method calls in Rust?