从函数中返回特征

4
我已经查看了rust库:https://github.com/cyderize/rust-websocket/ 在源文件https://github.com/cyderize/rust-websocket/blob/master/src/client/response.rs中,我看到了begin()方法:
pub fn begin(self) -> Client<DataFrame, Sender<W>, Receiver<R>> {
    let (reader, writer) = self.into_inner();
    let sender = Sender::new(writer);
    let receiver = Receiver::new(reader);
    Client::new(sender, receiver)
}

所以...我决定创建一些简单的封装函数:

fn get_transport(url: &str)  ->  Client<DataFrame, Sender<Write>, Receiver<Read>> {
    let url = Url::parse(url).unwrap();
    let request = Client::connect(url).unwrap();
    let response = request.send().unwrap();
    let mut ws = response.begin();

    ws
}

但是不幸的是,我得到了错误的结果:
error: the trait `core::marker::Sized` is not implemented for the type `websocket::ws::sender::Sender<std::io::Write>` [E0277]
src/lib.rs:36 fn get_transport(url: &str)  ->  Client<DataFrame, Sender<Write>, Receiver<Read>> {

请问有人能告诉我为什么我不能用这种方式返回值。与response.rs中的begin()方法有何区别? 在我的情况下应该如何返回值?

更新1: 在@ker的建议下,我有了下面的代码:

fn get_transport<W: Write, R: Read, S: Sender<W>, RE: Receiver<R>>(url: &str) -> Client<DataFrame, S, RE> {

    let url = Url::parse(url).unwrap();
    let request = Client::connect(url).unwrap();
    let response = request.send().unwrap();
    let mut ws = response.begin();

    ws
}

但在下一次编译中,出现了以下错误:
src/lib.rs:45:5: 45:7 error: mismatched types:
 expected `websocket::client::Client<websocket::dataframe::DataFrame, S, RE>`,
    found `websocket::client::Client<websocket::dataframe::DataFrame, websocket::client::sender::Sender<websocket::stream::WebSocketStream>, websocket::client::receiver::Receiver<websocket::stream::WebSocketStream>>`
(expected type parameter,
    found struct `websocket::client::sender::Sender`) [E0308]
src/lib.rs:45     ws
                  ^~
src/lib.rs:45:5: 45:7 help: run `rustc --explain E0308` to see a detailed explanation
error: aborting due to previous error

看起来我使用了错误的发送者和接收者:\ 在对部分进行更正后,我获得了结果代码:

fn get_transport(url: &str) -> Client<DataFrame, Sender<WebSocketStream>, Receiver<WebSocketStream>> {
    let url = Url::parse(url).unwrap();
    let request = Client::connect(url).unwrap();
    let response = request.send().unwrap();
    let mut ws = response.begin();

    ws
}

很抱歉,我无法找出为什么无法将泛型用作结果值。就像这样:

fn get_transport<R: Read, W: Write>(url: &str) -> Client<DataFrame, Sender<W>, Receiver<R>>

在这种情况下,我会收到错误信息:
expected `websocket::client::Client<websocket::dataframe::DataFrame, websocket::client::sender::Sender<W>, websocket::client::receiver::Receiver<R>>`,
    found `websocket::client::Client<websocket::dataframe::DataFrame, websocket::client::sender::Sender<websocket::stream::WebSocketStream>, websocket::client::receiver::Receiver<websocket::stream::WebSocketStream>>`
(expected type parameter,
    found enum `websocket::stream::WebSocketStream`) [E0308]
src/lib.rs:45     ws
                  ^~
2个回答

3

由于任何类型都可以实现trait,因此仅知道它实现的trait,就无法知道对象的大小。您可以将函数定义为在实现Write和Read trait的类型上进行通用,这样您就可以返回对象,而不知道对象的实际类型。

fn get_transport<W: Write, R: Read, S: Sender<W>, RE: Receiver<R>>(url: &str) -> Client<DataFrame, S, RE> {
    let url = Url::parse(url).unwrap();
    let request = Client::connect(url).unwrap();
    let response = request.send().unwrap();
    let mut ws = response.begin();

    ws
}

添加范型的原因在于,范型标签指向实际类型,且不需要知道任何关于该类型的信息,只需知道该类型实现了哪些特性。

1
是的,我明白你的观点。Writer、Reader不是Sized类型。但我不明白在这种情况下如何添加泛型标签会有所帮助? 此外,我尝试将这些更改添加到函数中,但仍然遇到类似的错误。也许我应该在不同的方式下构建源代码?最后一个错误信息(以防万一): 错误:对于类型websocket::ws::sender::Sender<W>,未实现特性core::marker::Sized [E0277] - slavamnemonic
您可以在此处找到它:https://github.com/cyderize/rust-websocket/blob/master/src/client/sender.rs - oli_obk
他们为该“Sender”类型实现了“ws::Sender”。 - oli_obk
谢谢你的帮助。你已经为我澄清了Rust中的泛型。不幸的是,我在导入Sender和Reader时犯了错误。项目有相同名称的结构体和特征。 也许你可以指点我正确的关于Rust泛型的文本。似乎Rust泛型比我预期的要深入得多。另外,你能否请检查UPD1并评论为什么在特征的情况下我会收到错误。正如我在rust-websocket项目源代码中看到的,begin()方法返回特征。对我来说不清楚为什么我不能返回带有<Write>特征的Sender。 - slavamnemonic
当您使用泛型时,泛型函数的调用者决定要期望哪些类型。在这里,您正在强制指定WR泛型的类型。这被称为特化,很可能不是您想要的。您可以简单地删除泛型并返回实际类型websocket::client::Client<websocket::dataframe::DataFrame, websocket::client::sender::Sender<websocket::stream::WebSocketStream>, websocket::client::receiver::Receiver<websocket::stream::WebSocketStream>>,这正是错误消息告诉您的。 - oli_obk
显示剩余2条评论

1
你想要用具体类型替换返回类型中的WriteSend
尝试将let mut ws = response.begin();改为let mut ws: () = response.begin(),你会看到一个错误消息,告诉你从begin函数返回了哪些具体类型。

我按照您的建议进行了测试。实际上,从一开始我就从这个步骤开始了。不管怎样,在处理ws:() = ...的情况时,我收到了错误:found struct 'websocket::client::Client') [E0308]。因此,下一步是将此结构设置为返回类型。<code> fn get_transport<W: Write, R: Read>(url: &str) -> websocket::client::Client { let url = Url::parse(url).unwrap(); let request = Client::connect(url).unwrap(); let response = request.send().unwrap(); let mut ws = response.begin(); ws } </code> 错误: src/lib.rs: 36:51: 36:76 错误:类型参数数量错误:期望3个,发现0个[E0243] - slavamnemonic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接