为什么编译器说该参数没有实现所需的特征?
Why compiler says that argument doesn't implement required traits?
不久前我开始学习 Rust 语言,现在我正在为个人项目实现一个 websocket 服务器。话虽如此,我不是专业的 Rust 程序员,我仍处于学习基础知识的阶段。
我用三个库开发这个项目,tokio
、hyper
和 tokio-tungstenite
。我的 HTTP 服务器是用 hyper
编写的。基本上只有一个处理程序。此处理程序做一件事,将传入的 UPGRADE HTTP 请求升级为 WebSocket 连接。
use std::str;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::prelude::*;
use hyper::header::{HeaderValue, UPGRADE, SEC_WEBSOCKET_ACCEPT};
use hyper::service::{make_service_fn, service_fn};
use hyper::upgrade::Upgraded;
use hyper::{Body, Client, Request, Response, Server, StatusCode};
use std::net::SocketAddr;
// A simple type alias so as to DRY.
type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
async fn server_upgrade(req: Request<Body>) -> Result<Response<Body>> {
let mut res = Response::new(Body::empty());
// Send a 400 to any request that doesn't have
// an `Upgrade` header.
if !req.headers().contains_key(UPGRADE) {
*res.status_mut() = StatusCode::BAD_REQUEST;
return Ok(res);
}
// Setup a future that will eventually receive the upgraded
// connection and talk a new protocol, and spawn the future
// into the runtime.
//
// Note: This can't possibly be fulfilled until the 101 response
// is returned below, so it's better to spawn this future instead
// waiting for it to complete to then return a response.
let upgraded: Upgraded = match req.into_body().on_upgrade().await {
Ok(upgraded) => upgraded,
Err(e) => {
eprintln!("upgrade error: {}", e);
return Err(Box::new(e));
},
};
tokio_tungstenite::accept_async(upgraded);
Ok(res)
}
在最后第 3 行,编译器发出一条错误消息:
the trait bound `hyper::upgrade::Upgraded: tokio::io::async_read::AsyncRead` is not satisfied
the trait `tokio::io::async_read::AsyncRead` is not implemented for `hyper::upgrade::Upgraded`
the trait bound `hyper::upgrade::Upgraded: tokio::io::async_write::AsyncWrite` is not satisfied
the trait `tokio::io::async_write::AsyncWrite` is not implemented for `hyper::upgrade::Upgraded`
但是当我查看 hyper::upgrade::Upgraded, I can see that it actually implements those traits. As I also look at the tokio-tunsgstenite 的文档时,确实这些特征是来自同一个板条箱的相同特征。
有经验的 rustecean 能帮我解决这个问题并让编译器相信 upgraded
实例实现了相同的特征吗?也许板条箱之间的版本不匹配?
我还附上了我的 Cargo.toml
文件。
[package]
name = "async-rs"
version = "0.1.0"
authors = ["Bora Semiz <Bora Semiz's email address>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
hyper = "0.13.9"
tokio = { version = "^0.2", features = ["full"] }
tokio-tungstenite = "0.12.0"
Hyper 使用的是 Tokio 版本 0.2.x
,而 tokio-tungstenite 使用的是 Tokio 版本 0.3.x
。从 Tokio 0.2
到 0.3
的变更日志包括对 AsyncRead
和 AsyncWrite
特性的重大更改,使这两个特性与其版本 0.2
不兼容。
您可以使用 tokio_compat_02 crate 连接两者,直到 Hyper 发布新版本(同时将您自己的 tokio
版本升级到 Cargo.toml
中的 0.3
),或者将 tokio-tungstenite 降级为 0.11.0
,如果您愿意,它使用 tokio 0.2.x
。
不久前我开始学习 Rust 语言,现在我正在为个人项目实现一个 websocket 服务器。话虽如此,我不是专业的 Rust 程序员,我仍处于学习基础知识的阶段。
我用三个库开发这个项目,tokio
、hyper
和 tokio-tungstenite
。我的 HTTP 服务器是用 hyper
编写的。基本上只有一个处理程序。此处理程序做一件事,将传入的 UPGRADE HTTP 请求升级为 WebSocket 连接。
use std::str;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::prelude::*;
use hyper::header::{HeaderValue, UPGRADE, SEC_WEBSOCKET_ACCEPT};
use hyper::service::{make_service_fn, service_fn};
use hyper::upgrade::Upgraded;
use hyper::{Body, Client, Request, Response, Server, StatusCode};
use std::net::SocketAddr;
// A simple type alias so as to DRY.
type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
async fn server_upgrade(req: Request<Body>) -> Result<Response<Body>> {
let mut res = Response::new(Body::empty());
// Send a 400 to any request that doesn't have
// an `Upgrade` header.
if !req.headers().contains_key(UPGRADE) {
*res.status_mut() = StatusCode::BAD_REQUEST;
return Ok(res);
}
// Setup a future that will eventually receive the upgraded
// connection and talk a new protocol, and spawn the future
// into the runtime.
//
// Note: This can't possibly be fulfilled until the 101 response
// is returned below, so it's better to spawn this future instead
// waiting for it to complete to then return a response.
let upgraded: Upgraded = match req.into_body().on_upgrade().await {
Ok(upgraded) => upgraded,
Err(e) => {
eprintln!("upgrade error: {}", e);
return Err(Box::new(e));
},
};
tokio_tungstenite::accept_async(upgraded);
Ok(res)
}
在最后第 3 行,编译器发出一条错误消息:
the trait bound `hyper::upgrade::Upgraded: tokio::io::async_read::AsyncRead` is not satisfied
the trait `tokio::io::async_read::AsyncRead` is not implemented for `hyper::upgrade::Upgraded`
the trait bound `hyper::upgrade::Upgraded: tokio::io::async_write::AsyncWrite` is not satisfied
the trait `tokio::io::async_write::AsyncWrite` is not implemented for `hyper::upgrade::Upgraded`
但是当我查看 hyper::upgrade::Upgraded, I can see that it actually implements those traits. As I also look at the tokio-tunsgstenite 的文档时,确实这些特征是来自同一个板条箱的相同特征。
有经验的 rustecean 能帮我解决这个问题并让编译器相信 upgraded
实例实现了相同的特征吗?也许板条箱之间的版本不匹配?
我还附上了我的 Cargo.toml
文件。
[package]
name = "async-rs"
version = "0.1.0"
authors = ["Bora Semiz <Bora Semiz's email address>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
hyper = "0.13.9"
tokio = { version = "^0.2", features = ["full"] }
tokio-tungstenite = "0.12.0"
Hyper 使用的是 Tokio 版本 0.2.x
,而 tokio-tungstenite 使用的是 Tokio 版本 0.3.x
。从 Tokio 0.2
到 0.3
的变更日志包括对 AsyncRead
和 AsyncWrite
特性的重大更改,使这两个特性与其版本 0.2
不兼容。
您可以使用 tokio_compat_02 crate 连接两者,直到 Hyper 发布新版本(同时将您自己的 tokio
版本升级到 Cargo.toml
中的 0.3
),或者将 tokio-tungstenite 降级为 0.11.0
,如果您愿意,它使用 tokio 0.2.x
。