关联类型以通过特征和泛型类型规范化可序列化数据
Associated types to normalize serializable data via traits and a generic type
我试图实现一种类型,该类型将 "enforce" 一些模式用于我在 Tide 中的响应,但不断收到 "Items from traits can only be used..." 编译器错误。
#![feature(async_await, futures_api, await_macro, arbitrary_self_types)]
#![allow(proc_macro_derive_resolution_fallback)]
use serde_derive::Serialize;
use tide::{body::Json, IntoResponse, Response};
#[derive(Serialize)]
struct Document<Attrs, Rels> {
data: PrimaryData<Attrs, Rels>,
}
#[derive(Serialize)]
struct PrimaryData<Attrs, Rels> {
id: i32,
kind: String,
attributes: Attrs,
relationships: Rels,
}
trait IntoPrimaryData: Send {
type Attrs: serde::Serialize;
type Rels: serde::Serialize;
fn into_primary_data(self) -> PrimaryData<Self::Attrs, Self::Rels>;
}
struct ServiceResponse<T: IntoPrimaryData>(T);
impl<T: IntoPrimaryData> IntoResponse for ServiceResponse<T> {
fn into_response(self) -> Response {
Json(Document {
data: self.0.into_primary_data(),
})
.with_status(http::status::StatusCode::OK)
.into_response()
}
}
#[derive(Serialize)]
struct User {
id: i32,
primary_email: String,
}
#[derive(Serialize)]
struct UserAttrs {
primary_email: String,
}
impl IntoPrimaryData for User {
type Attrs = UserAttrs;
type Rels = ();
fn into_primary_data(self) -> PrimaryData<Self::Attrs, Self::Rels> {
PrimaryData {
id: self.id,
kind: "user".into(),
attributes: UserAttrs {
primary_email: self.primary_email,
},
relationships: (),
}
}
}
fn main() {}
[dependencies]
tide = "0.0.5"
http = "0.1.16"
serde = "1.0.89"
serde_derive = "1.0.89"
编译器returns错误
error[E0599]: no method named `with_status` found for type `tide::body::Json<Document<<T as IntoPrimaryData>::Attrs, <T as IntoPrimaryData>::Rels>>` in the current scope
--> src/main.rs:34:10
|
34 | .with_status(http::status::StatusCode::OK)
| ^^^^^^^^^^^
|
= note: the method `with_status` exists but the following trait bounds were not satisfied:
`tide::body::Json<Document<<T as IntoPrimaryData>::Attrs, <T as IntoPrimaryData>::Rels>> : tide::response::IntoResponse`
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `with_status`, perhaps you need to implement it:
candidate #1: `tide::response::IntoResponse`
我不确定为什么会收到此错误,但我觉得这与 data: self.0.into_primary_data()
行不够 "specific" 行有关,并且不知道是什么Self::Attrs
和 Self::Rels
的类型是。但是,我知道如果其中一个嵌套类型没有实现 serde::Serialize
,我也会遇到同样的错误(减去关于 "items from traits can only be..." 的帮助提示),但据我所知,我已经添加了那些在他们需要的任何地方都有界限。
我已经尝试过用一百万种方式来做这件事,但似乎无法想出一种方法来为我的回答获得一些规范化的结构。
我正在使用 rustc 1.34.0-nightly (02c4c2892 2019-02-26)
您没有正确指定关联类型的完整范围。
Json
仅在其包含的类型同时实现 Send
和 Serialize
:
时才实现 IntoResponse
impl<T: Send + Serialize> IntoResponse for Json<T>
您需要在关联类型的边界中包含 Send
:
trait IntoPrimaryData: Send {
type Attrs: serde::Serialize + Send;
// ^^^^^^
type Rels: serde::Serialize + Send;
// ^^^^^^
fn into_primary_data(self) -> PrimaryData<Self::Attrs, Self::Rels>;
}
调试步骤
这行错误消息看起来很有希望:
the method `with_status` exists but the following trait bounds were not satisfied:
`tide::body::Json<Document<<T as IntoPrimaryData>::Attrs, <T as IntoPrimaryData>::Rels>> : tide::response::IntoResponse`
这表明我们可以调用 with_status
,除非编译器不知道该类型实现了特征。从那里,我去了 Json
的文档,看看它是否实现了 IntoRespose
如果是,在什么条件下:
impl<T: Send + Serialize> IntoResponse for Json<T>
据此,我们知道这个T
必须是PrimaryData<T::Attrs, T::Rels>
并且它必须实现Send + Serialize
。
我们看到 PrimaryData
导出 Serialize
:
#[derive(Serialize)]
struct PrimaryData<Attrs, Rels> {
根据现有知识,我知道大多数 derive
d 特征都要求所有泛型类型也实现该特征。它不太明显,但对于 Send
.
也是如此
从那里开始,就是要证明 Attrs
和 Rels
的特定类型实现了 Serialize
和 Send
。关联的类型边界处理一个但不处理另一个。
决定在哪里放置边界是一个意图和风格的问题——它们可以在函数、impl
块或特征中继续。由于该特征已经提到 Serialize
,因此添加额外的界限似乎是一个自然的地方。
我也犯了一个大错误——我假设你已经正确指定了边界并且 运行 变成了 ()。只有当我尝试应用建议的副本时,我才意识到边界不正确。
另请参阅:
我试图实现一种类型,该类型将 "enforce" 一些模式用于我在 Tide 中的响应,但不断收到 "Items from traits can only be used..." 编译器错误。
#![feature(async_await, futures_api, await_macro, arbitrary_self_types)]
#![allow(proc_macro_derive_resolution_fallback)]
use serde_derive::Serialize;
use tide::{body::Json, IntoResponse, Response};
#[derive(Serialize)]
struct Document<Attrs, Rels> {
data: PrimaryData<Attrs, Rels>,
}
#[derive(Serialize)]
struct PrimaryData<Attrs, Rels> {
id: i32,
kind: String,
attributes: Attrs,
relationships: Rels,
}
trait IntoPrimaryData: Send {
type Attrs: serde::Serialize;
type Rels: serde::Serialize;
fn into_primary_data(self) -> PrimaryData<Self::Attrs, Self::Rels>;
}
struct ServiceResponse<T: IntoPrimaryData>(T);
impl<T: IntoPrimaryData> IntoResponse for ServiceResponse<T> {
fn into_response(self) -> Response {
Json(Document {
data: self.0.into_primary_data(),
})
.with_status(http::status::StatusCode::OK)
.into_response()
}
}
#[derive(Serialize)]
struct User {
id: i32,
primary_email: String,
}
#[derive(Serialize)]
struct UserAttrs {
primary_email: String,
}
impl IntoPrimaryData for User {
type Attrs = UserAttrs;
type Rels = ();
fn into_primary_data(self) -> PrimaryData<Self::Attrs, Self::Rels> {
PrimaryData {
id: self.id,
kind: "user".into(),
attributes: UserAttrs {
primary_email: self.primary_email,
},
relationships: (),
}
}
}
fn main() {}
[dependencies]
tide = "0.0.5"
http = "0.1.16"
serde = "1.0.89"
serde_derive = "1.0.89"
编译器returns错误
error[E0599]: no method named `with_status` found for type `tide::body::Json<Document<<T as IntoPrimaryData>::Attrs, <T as IntoPrimaryData>::Rels>>` in the current scope
--> src/main.rs:34:10
|
34 | .with_status(http::status::StatusCode::OK)
| ^^^^^^^^^^^
|
= note: the method `with_status` exists but the following trait bounds were not satisfied:
`tide::body::Json<Document<<T as IntoPrimaryData>::Attrs, <T as IntoPrimaryData>::Rels>> : tide::response::IntoResponse`
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `with_status`, perhaps you need to implement it:
candidate #1: `tide::response::IntoResponse`
我不确定为什么会收到此错误,但我觉得这与 data: self.0.into_primary_data()
行不够 "specific" 行有关,并且不知道是什么Self::Attrs
和 Self::Rels
的类型是。但是,我知道如果其中一个嵌套类型没有实现 serde::Serialize
,我也会遇到同样的错误(减去关于 "items from traits can only be..." 的帮助提示),但据我所知,我已经添加了那些在他们需要的任何地方都有界限。
我已经尝试过用一百万种方式来做这件事,但似乎无法想出一种方法来为我的回答获得一些规范化的结构。
我正在使用 rustc 1.34.0-nightly (02c4c2892 2019-02-26)
您没有正确指定关联类型的完整范围。
Json
仅在其包含的类型同时实现 Send
和 Serialize
:
IntoResponse
impl<T: Send + Serialize> IntoResponse for Json<T>
您需要在关联类型的边界中包含 Send
:
trait IntoPrimaryData: Send {
type Attrs: serde::Serialize + Send;
// ^^^^^^
type Rels: serde::Serialize + Send;
// ^^^^^^
fn into_primary_data(self) -> PrimaryData<Self::Attrs, Self::Rels>;
}
调试步骤
这行错误消息看起来很有希望:
the method `with_status` exists but the following trait bounds were not satisfied:
`tide::body::Json<Document<<T as IntoPrimaryData>::Attrs, <T as IntoPrimaryData>::Rels>> : tide::response::IntoResponse`
这表明我们可以调用 with_status
,除非编译器不知道该类型实现了特征。从那里,我去了 Json
的文档,看看它是否实现了 IntoRespose
如果是,在什么条件下:
impl<T: Send + Serialize> IntoResponse for Json<T>
据此,我们知道这个T
必须是PrimaryData<T::Attrs, T::Rels>
并且它必须实现Send + Serialize
。
我们看到 PrimaryData
导出 Serialize
:
#[derive(Serialize)]
struct PrimaryData<Attrs, Rels> {
根据现有知识,我知道大多数 derive
d 特征都要求所有泛型类型也实现该特征。它不太明显,但对于 Send
.
从那里开始,就是要证明 Attrs
和 Rels
的特定类型实现了 Serialize
和 Send
。关联的类型边界处理一个但不处理另一个。
决定在哪里放置边界是一个意图和风格的问题——它们可以在函数、impl
块或特征中继续。由于该特征已经提到 Serialize
,因此添加额外的界限似乎是一个自然的地方。
我也犯了一个大错误——我假设你已经正确指定了边界并且 运行 变成了
另请参阅: