Как фреймворк Iron применяет кортеж модификаторов к Response::with?

Я просматриваю исходный код Iron для Response::with(), пытаясь понять, как он применяет кортеж в качестве модификаторов к ответу.

Насколько я понимаю, модификатор — это просто объект-конструктор, принимающий ссылку на текущий контекст (self) и принимающий объект, на котором вы хотите построить, в качестве параметра (пока вы реализуете функцию modify).

Предположим, у нас есть следующий код:

use iron::modifiers::Header;

fn hello_world(_: &mut Request) -> IronResult<Response> {
    let string = get_file_as_string("./public/index.html");
    let content_type = Header(ContentType(Mime(TopLevel::Text, SubLevel::Html, vec![])));
    Ok(Response::with((status::Ok, string, content_type)))
}

Копаясь в документах, я вижу, что реализация Response::with() в Iron выглядит следующим образом:

pub fn new() -> Response {
    Response {
        status: None, // Start with no response code.
        body: None, // Start with no body.
        headers: Headers::new(),
        extensions: TypeMap::new()
    }
}

/// Construct a Response with the specified modifier pre-applied.
pub fn with<M: Modifier<Response>>(m: M) -> Response {
    Response::new().set(m)
}

Я изо всех сил пытаюсь понять, как мой кортеж объектов преобразуется в модификаторы? Я ожидал увидеть, что foreach потенциально перебирает каждый модификатор, но здесь я просто вижу операцию набора.

Может ли кто-нибудь объяснить здесь порядок казни и раскрыть, что на самом деле происходит?


person Jacob Clark    schedule 24.05.2016    source источник


Ответы (1)


Интересный вопрос! Давайте еще раз посмотрим на сигнатуру функции:

fn with<M: Modifier<Response>>(m: M) -> Response

Это означает, что with принимает ровно один аргумент, реализующий Modifier<Response>. Итак, далее мы можем посмотреть, какие типы реализуют трейт Modifier. В документации мы видим, что это реализовано не только для String или Status, но и для типов кортежей! Эти реализации написаны в этом файле. Например, давайте посмотрим на этот импл:

impl<X, M1, M2, M3> Modifier<X> for (M1, M2, M3)
    where M1: Modifier<X>,
          M2: Modifier<X>,
          M3: Modifier<X> 
{
    fn modify(self, x: &mut X) {
        self.0.modify(x);
        self.1.modify(x);
        self.2.modify(x);
    }
}

Это реализует трейт для каждого кортежа размера 3, элементы которого также реализуют Modifier. А реализация modify состоит всего лишь в том, чтобы вызвать modify-реализацию каждого элемента кортежа; это foreach, который вы искали.

person Lukas Kalbertodt    schedule 24.05.2016
comment
Спасибо за блестящий ответ, есть ли причина, по которой «Модификатор» реализует кортежи до 5, а не больше? - person Jacob Clark; 24.05.2016
comment
Я предполагаю, что просто раздражает набирать слишком много реализаций трейтов. - person aochagavia; 24.05.2016
comment
@JacobClark В основном то, что говорит aochagavia. Проблема в том, что Rust не предлагает функционала для реализации трейта для кортежей всех размеров. Поэтому каждую реализацию приходится писать вручную (более или менее) и добавлять в проект больше кода. Так что вам нужно остановиться в какой-то момент... Iron решил, что 5 - это хорошая точка для остановки ;) - person Lukas Kalbertodt; 24.05.2016