在python中,我可能有这样一个类:

class ClientObject(object):

    def __init__(self):
        connection = None
        connected = False

    def connect(self):
        self.connection = new Connection('server')
        self.connected = True

    def disconnect(self):
        self.connection.close()
        self.connection = None
        self.connected = False

我正在try 做类似的事情.首先,我怀疑这在rust中是否是一个好模式——您会用这种方式实现一个具有连接的客户机类吗?第二,我在实现中遇到了一个我不理解的错误.

pub struct Client {
    seq: int,
    connected: bool,
    socket: Option<UdpSocket>
}

impl Client {

    pub fn connect(&mut self, addr: &SocketAddr) -> ClientConnectionResult {
        match self.socket {
            Some(_) => self.disconnect(),
            None => ()
        };

        self.socket = match UdpSocket::bind(*addr) {
            Ok(s) => Some(s),
            Err(e) => return Err(to_client_error(e))
        };

        self.connected = true;

        Ok(())
    }

    pub fn disconnect(&mut self) {
        match self.socket {
            None => (),
            Some(s) => drop(s)
        };

        self.socket = None;

        self.connected = false;
    }
}

在disconnect函数中,匹配会生成一个编译错误,因为它试图移动self的所有权.插座我想做的是让自己.socket设置为None,并允许在调用connect时将其重新分配给某个对象.我该怎么做?

推荐答案

它可能不适用于您的用例,但当一个方法消耗self(当前状态)并返回另一个表示另一个状态的对象时,Rust move语义和强类型允许廉价的"状态机".TcpListener就是这样实现的:它有listen()个方法,返回TcpAcceptor,在这个过程中使用原始侦听器.这种方法有键入的优点:当对象处于无效状态时,无法调用没有意义的方法.

在你的情况下,它可能看起来像这样:

use std::kinds::markers::NoCopy;

pub struct DisconnectedClient {
    seq: int,
    _no_copy: NoCopy
}

impl DisconnectedClient {
    #[inline]
    pub fn new(seq: int) -> DisconnectedClient {
        DisconnectedClient { seq: seq, _no_copy: NoCopy }
    }

    // DisconnectedClient does not implement Copy due to NoCopy marker so you need 
    // to return it back in case of error, together with that error, otherwise 
    // it is consumed and can't be used again.
    pub fn connect(self, addr: &SocketAddr) -> Result<ConnectedClient, (DisconnectedClient, IoError)> {
        match UdpSocket::bind(*addr) {
            Ok(s) => Ok(ConnectedClient { seq: self.seq, socket: s }),
            Err(e) => Err((self, e))
        }
    }
}

pub struct ConnectedClient {
    seq: int,
    socket: UdpSocket
}

impl ConnectedClient {
    #[inline]
    pub fn disconnect(self) -> DisconnectedClient {
        // self.socket will be dropped here
        DisconnectedClient::new(self.seq)
    }

    // all operations on active connection are defined here
}

首先使用DisconnectedClient::new()方法创建DisconnectedClient.然后,当您想要连接到某个东西时,使用connect()方法,该方法消耗DisconnectedClient并返回新对象ConnectedClient,它表示已建立的连接.当您完成这个连接时,disconnect()方法将ConnectedClient变回DisconnectedClient.

这种方法可能更复杂,但它有静态判断错误状态的优势.你不必有connected()种类似的方法;如果变量的类型是ConnectedClient,那么您已经知道它是连接的.

Rust相关问答推荐

为什么我需要在这个代码示例中使用&

borrow 和内部IntoIterator

当Option为None时,Option数组是否占用Rust中的内存?

在Rust中,有没有一种方法让我定义两个 struct ,其中两个都遵循标准 struct ?

值为可变对象的不可变HashMap

亚性状上位性状上的 rust 病伴生型界限

在执行其他工作的同时,从共享裁判后面的VEC中删除重复项

用 rust 蚀中的future 展望 struct 的future

将PathBuf转换为字符串

为什么铁 rust S的默认排序功能比我对小数组的 Select 排序稍微慢一些?

为什么';t std::cell::ref使用引用而不是非空?

Rust函数的返回值不能引用局部变量或临时变量

使用 select 处理 SIGINT 和子等待!无阻塞

使用 Option 来分配?

Rust 并行获取对 ndarray 的每个元素的可变引用

decltype、dyn、impl traits,重构时如何声明函数的返回类型

了解 Rust 闭包:为什么它们持续持有可变引用?

不能将 `*self` borrow 为不可变的,因为它也被borrow 为可变的 - 编译器真的需要如此严格吗?

Rust/Serde/HTTP:序列化`Option`

基于名称是否存在的条件编译