compiler-errors - 通过特征和泛型类型来规范化可序列化数据的关联类型

标签 compiler-errors scope rust traits

我尝试实现一种类型,该类型可以对 Tide 中的响应“强制”某些模式。但不断收到“来自特征的项目只能使用...”编译器错误。

#![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"

编译器返回错误

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() 行不够“具体”有关,并且不知道 Self::AttrsSelf::Rels 的类型是什么。但是,我知道如果其中一种嵌套类型未实现 serde::Serialize,我也会遇到同样的错误(减去有关“来自特征的项目只能是...”的帮助提示)但据我所知,我已经在需要的地方添加了这些边界。

我现在已经尝试过一百万种方法来做到这一点,但似乎无法想出一种方法来为我的回答获得一些标准化的结构。

我正在使用rustc 1.34.0-nightly (02c4c2892 2019-02-26)

最佳答案

您尚未正确指定关联类型的完整边界。

Json 仅实现 IntoResponse当它包含的类型同时实现 Send 时和Serialize :

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实现SerializeSend 。关联的类型边界处理其中之一,但不处理另一个。

决定在哪里放置边界是意图和风格的问题 - 他们可以继续使用函数,impl block 或特征中。由于该特征已经提到了 Serialize ,这似乎是添加额外边界的自然位置。

我还犯了一个很大的错误——我以为你已经正确指定了边界并且遇到了a compiler limitation (also)。只有当我尝试应用建议的重复项时,我才意识到边界不正确。

另请参阅:

关于compiler-errors - 通过特征和泛型类型来规范化可序列化数据的关联类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55144134/

相关文章:

c++ - 错误 127 g++ : Command not found

android - 关于主要 Activity : 'illegal start of expression' 的错误消息

ruby - 由 Rufus Scheduler 触发的 Sinatra 事件

python - Dask dataframe apply 在传递局部变量作为参数时给出意外的结果

rust - 是否有针对 Rc 或 Arc 的操作可以克隆基础值并将其返回给调用者?

c++ - 无法在Debian Linux中编译C++ 17

Java 可执行 Jar 文件

混淆 while 和 for 循环的变量作用域(C 编程)

rust - 为什么使用 "Self"作为参数类型会引发生命周期错误?

rust - impl block 不需要泛型参数的生命周期限制