在包装函数中借用struct中的内部数据

时间:2015-10-14 03:18:53

标签: rust

我一直致力于使图书馆(rust-websocket)使用更多借阅和更少拥有的数据。这涉及向结构添加Cow,其中包括为该结构添加生命周期,这使得整个库需要生命周期。

总之,我还有一个问题,而且我已经试图解决它好几天了。可以使用以下代码进行总结:

{   // This works great!
    let mut sender = Wire;
    let message = Text("Hello World!".to_string());
    sender.send_message(&message);
}
{   // This DOES NOT COMPILE!
    let mut client = Client {
        sender: Wire,
        packet: PhantomData,
    };
    let message = Text("Hello World!".to_string());
    client.send(&message);
}

在上面的示例中,client.sendsender.send_message的包装器,两者具有相同的定义。虽然在client.send的情况下,发送的邮件必须比客户端更长。在sender.send_message情况下,消息只需要在函数调用的生命周期内存活。

use std::borrow::Cow;
use std::iter::{Take, Repeat, repeat};
use std::marker::PhantomData;

trait Sender<P> {
    fn send_packet(&mut self, packet: &P) -> Result<(), ()>;

    fn send_message<'m, M>(&mut self, message: &'m M) -> Result<(), ()>
        where M: Message<'m, P>,
              P: 'm
    {
        for ref packet in message.iter() {
            try!( self.send_packet(packet) );
        }
        Ok(())
    }
}

trait Message<'p, P>
    where P: 'p
{
    type PacketIterator: Iterator<Item = P>;
    fn iter(&'p self) -> Self::PacketIterator;
}

#[derive(Clone, Debug)]
struct Packet<'d> {
    data: Cow<'d, [u8]>,
}

struct Text(String);

impl<'p> Message<'p, Packet<'p>> for Text {
    type PacketIterator = Take<Repeat<Packet<'p>>>;

    fn iter(&'p self) -> Take<Repeat<Packet<'p>>> {
        repeat(Packet {
            data: Cow::Borrowed(self.0.as_bytes()),
        }).take(1)
    }
}

struct Wire;

impl<'s> Sender<Packet<'s>> for Wire {
    fn send_packet<'p>(&mut self, packet: &Packet<'p>) -> Result<(), ()> {
        println!("Sent {:?}", packet);
        Ok(())
    }
}

struct Client<P, S> {
    sender: S,
    packet: PhantomData<P>
}

impl<P, S> Client<P, S>
    where S: Sender<P>
{
    fn send<'m, M>(&mut self, message: &'m M) -> Result<(), ()>
        where M: Message<'m, P>,
              P: 'm
    {
        self.sender.send_message(message)
    }
}

fn main() {
    {   // This works great!
        let mut sender = Wire;
        let message = Text("Hello World!".to_string());
        sender.send_message(&message);
    }
    {   // This DOES NOT COMPILE!
        let mut client = Client {
            sender: Wire,
            packet: PhantomData,
        };
        let message = Text("Hello World!".to_string());
        client.send(&message);
    }
}

我把整个code on the Rust Playground

我希望我能更好地描述我的问题,以便更好地搜索,所以一旦我知道发生了什么,我就会改变我的头衔。

1 个答案:

答案 0 :(得分:3)

PhantomData<P>更改为PhantomData<fn(P)>。您的类型不会存储P,而是会在P上运行。

此处的问题是您声称​​存储 P,这意味着类型P必须比类型Client<S, P>更长。要使P(数据包类型)比Client类型更长,message本身必须比client更长,因为您要从邮件中借用数据包。但是,在这种情况下,clientmessage更长,因为client首先在堆栈上分配(堆栈以相反的顺序拆除)。