如果不实现 Copy 或 Clone 特征,重用借用的结构字段的最佳方法是什么?
What is the best way to reuse a borrowed struct field if it doesn't implement the Copy or Clone trait?
我正在为 TCP 服务器编写客户端
use std::net::TcpStream;
use std::io::{Read, Write, Error};
pub struct Client {
addr: String,
conn: Option<TcpStream>,
}
impl Client {
pub fn connect(&mut self) {
let res = TcpStream::connect(&self.addr);
match res {
Ok(c) => {
self.conn = Some(c);
},
Err(_) => panic!(),
}
}
pub fn version(self) -> Result<[u8; 8], Error> {
let mut ver: [u8; 8] = [0;8];
let command_string = b"VERSION\r\n";
let res = self.conn.unwrap().write(&command_string[0..]);
match res {
Ok(_) => self.conn.unwrap().read(&mut ver[..]),
Err(e) => panic!(e)
};
Ok(ver)
}
}
版本方法returns错误
error[E0382]: use of moved value: `self.conn`
当我尝试重新使用参考时。我考虑过使用 #[derive(Copy, Clone)]
但由于这些特性没有为 TCPStream 实现,我不确定该怎么做。在一个方法中实现读取和写入服务器的最佳方法是什么(顺便说一句,会有很多这样的方法,比如既可以读取也可以写入服务器的版本)
我对 Rust 还是个新手,并试图围绕所有权概念思考,所以如果这是一个愚蠢的问题,我深表歉意,但因为我想讨论各种方法(如果确实有多种方法来解决这个问题) reuse un-Clonable/Copyable fields 我认为这个问题值得一问。
The version method returns an error when I try to reuse the reference
self.conn
不是引用;这是一个拥有的价值。因为 Option::unwrap
按值获取它(并且它的类型没有实现 Copy
),所以在调用 .unwrap()
之后不能重用它;那会导致不安全。
但是您可以将调用 unwrap
的结果存储到一个新变量中,然后改用它:
pub fn version(self) -> io::Result<[u8; 8]> {
let mut ver: [u8; 8] = [0;8];
const COMMAND_STRING: &[u8] = b"VERSION\r\n";
let mut conn = self.conn.unwrap();
conn.write(COMMAND_STRING)?;
conn.read(&mut ver[..])?;
Ok(ver)
}
这是可能的,因为io::Write::write
和io::Read::read
都取&mut self
,这意味着两者都不需要按值取conn
。相反,conn
将在 version
的末尾删除。另见
我做了一些进一步的修改,你可以考虑这些建议:
io::Result<_>
是 Result<_, io::Error>
的别名,所以我更改了声明的 return 类型。这是许多库中的常见模式,我发现这种形式更容易快速理解。
conn.read()
returns 一个 io::Result
,之前被忽略了。现在 conn.write()
和 conn.read()
都使用特殊的 ?
运算符向调用者引发错误。如果你想让错误恐慌而不是传播,你可以用 .unwrap()
替换 ?
。参见
COMMAND_STRING
是一只 const
蚂蚁。与 conn.write(b"VERSION\r\n")
相比,使用这个名称是否有用还有待商榷,但如果您要使用它,const
似乎是正确的选择。原则上编译器可以比常规变量更好地优化 const
s;在实践中,在这种情况下不太可能产生太大差异,但是当 const
更明确地说明该值的使用方式时,没有理由不这样做。
使用实际参考
如果您确实希望 version
通过引用获取 self
,因此您 不希望 它解包并销毁 self.conn
,您可以使用 Option::as_ref
来完成这项工作。
pub fn version(&self) -> io::Result<[u8; 8]> { // NOTE: `&self`
let mut ver: [u8; 8] = [0;8];
let mut conn = self.conn.as_ref().unwrap(); // NOTE: `.as_ref()`
conn.write(b"VERSION\r\n")?;
conn.read(&mut ver[..])?;
Ok(ver)
}
as_ref
将 &Option<_>
变成 Option<&_>
,这样 unwrap
ping 就不会消耗 self.conn
而只是 returns参考资料。参见 。
我正在为 TCP 服务器编写客户端
use std::net::TcpStream;
use std::io::{Read, Write, Error};
pub struct Client {
addr: String,
conn: Option<TcpStream>,
}
impl Client {
pub fn connect(&mut self) {
let res = TcpStream::connect(&self.addr);
match res {
Ok(c) => {
self.conn = Some(c);
},
Err(_) => panic!(),
}
}
pub fn version(self) -> Result<[u8; 8], Error> {
let mut ver: [u8; 8] = [0;8];
let command_string = b"VERSION\r\n";
let res = self.conn.unwrap().write(&command_string[0..]);
match res {
Ok(_) => self.conn.unwrap().read(&mut ver[..]),
Err(e) => panic!(e)
};
Ok(ver)
}
}
版本方法returns错误
error[E0382]: use of moved value: `self.conn`
当我尝试重新使用参考时。我考虑过使用 #[derive(Copy, Clone)]
但由于这些特性没有为 TCPStream 实现,我不确定该怎么做。在一个方法中实现读取和写入服务器的最佳方法是什么(顺便说一句,会有很多这样的方法,比如既可以读取也可以写入服务器的版本)
我对 Rust 还是个新手,并试图围绕所有权概念思考,所以如果这是一个愚蠢的问题,我深表歉意,但因为我想讨论各种方法(如果确实有多种方法来解决这个问题) reuse un-Clonable/Copyable fields 我认为这个问题值得一问。
The version method returns an error when I try to reuse the reference
self.conn
不是引用;这是一个拥有的价值。因为 Option::unwrap
按值获取它(并且它的类型没有实现 Copy
),所以在调用 .unwrap()
之后不能重用它;那会导致不安全。
但是您可以将调用 unwrap
的结果存储到一个新变量中,然后改用它:
pub fn version(self) -> io::Result<[u8; 8]> {
let mut ver: [u8; 8] = [0;8];
const COMMAND_STRING: &[u8] = b"VERSION\r\n";
let mut conn = self.conn.unwrap();
conn.write(COMMAND_STRING)?;
conn.read(&mut ver[..])?;
Ok(ver)
}
这是可能的,因为io::Write::write
和io::Read::read
都取&mut self
,这意味着两者都不需要按值取conn
。相反,conn
将在 version
的末尾删除。另见
我做了一些进一步的修改,你可以考虑这些建议:
io::Result<_>
是Result<_, io::Error>
的别名,所以我更改了声明的 return 类型。这是许多库中的常见模式,我发现这种形式更容易快速理解。conn.read()
returns 一个io::Result
,之前被忽略了。现在conn.write()
和conn.read()
都使用特殊的?
运算符向调用者引发错误。如果你想让错误恐慌而不是传播,你可以用.unwrap()
替换?
。参见COMMAND_STRING
是一只const
蚂蚁。与conn.write(b"VERSION\r\n")
相比,使用这个名称是否有用还有待商榷,但如果您要使用它,const
似乎是正确的选择。原则上编译器可以比常规变量更好地优化const
s;在实践中,在这种情况下不太可能产生太大差异,但是当const
更明确地说明该值的使用方式时,没有理由不这样做。
使用实际参考
如果您确实希望 version
通过引用获取 self
,因此您 不希望 它解包并销毁 self.conn
,您可以使用 Option::as_ref
来完成这项工作。
pub fn version(&self) -> io::Result<[u8; 8]> { // NOTE: `&self`
let mut ver: [u8; 8] = [0;8];
let mut conn = self.conn.as_ref().unwrap(); // NOTE: `.as_ref()`
conn.write(b"VERSION\r\n")?;
conn.read(&mut ver[..])?;
Ok(ver)
}
as_ref
将 &Option<_>
变成 Option<&_>
,这样 unwrap
ping 就不会消耗 self.conn
而只是 returns参考资料。参见