Arhn - архитектура программирования

Можно ли присвоить замыкание переменной типа impl Fn()?

Я смог заставить этот код работать:

fn twice<T: Clone>(fst: impl Fn(T), snd: impl Fn(T)) -> impl Fn(T) {
    move |t| {
        fst(t.clone());
        snd(t)
    }
}

Однако я хочу этого (без бокса):

fn sub<T: Clone>(mut fst: impl Fn(T), snd: impl Fn(T)) {
    fst = move |t: T| {
        fst(t.clone());
        snd(t)
    };
}

Есть ли способ заставить вторую часть кода работать без упаковки, использования трейтов, приведения типов или любого другого метода? Rust жалуется, что типы не совпадают.

19.01.2019

  • Сначала ваш подход неверен, вы перемещаете fst в функцию sub, а затем пытаетесь изменить ее значение. но ничего не возвращает? fst будет удален внутри подфункции. 19.01.2019

Ответы:


1

Без бокса это невозможно. Причина в том, что фактический тип fst во входных данных отличается от типа замыкания, которым вы позже перезапишете его. Единственный способ сделать их одного типа — использовать трейт-объект.

Коробочная версия может выглядеть так:

use std::mem;

fn sub<'a, T: Clone + 'a>(fst: &mut Box<dyn Fn(T) + 'a>, snd: impl Fn(T) + 'a) {
    // Replace the original fst with a dummy closure while the new closure is being
    // constructed, to avoid the reference being temporarily invalid
    let fst_orig = mem::replace(fst, Box::new(|_| {}));
    *fst = Box::new(move |t: T| {
        fst_orig(t.clone());
        snd(t)
    });
}


fn main() {
    let mut f1: Box<dyn Fn(i32)> = Box::new(|x| println!("f1: {}", x));
    let f2 = |x| println!("f2: {}", x);

    sub(&mut f1, f2);

    f1(42);
}

Но я действительно не уверен, почему вы хотели бы сделать это!

19.01.2019
  • А также этот простой код , проверьте ошибку, она говорит: примечание: никакие два замыкания, даже если они идентичны, не имеют одного и того же типа, помогите: подумайте о том, чтобы упаковать ваше замыкание и/или использовать его в качестве типаж-объекта 19.01.2019
  • Но я действительно не уверен, зачем вам это нужно! — Это 100%. Просто переназначьте fst и дайте ему новый тип. 20.01.2019
  • @Shepmaster На самом деле я сделал предположение, что OP хотел перезаписать входной указатель fn, что не совсем было выражено в вопросе. Вот почему я включил пример main, в котором используется решение. Если бы это был просто вопрос повторного использования имени переменной внутри функции, это казалось бы слишком тривиальным запросом, но, может быть, это то, чего на самом деле хотел OP? 20.01.2019

  • 2

    Отвечая на вопрос, который вы задали, нет, вы пока не можете присвоить замыкание переменной с типом impl Fn, потому что вы еще не можете объявить такую ​​переменную:

    fn foo() {
        let x: impl Fn() = move || println!("Hello");
    }
    
    error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
     --> src/lib.rs:2:12
      |
    2 |     let x: impl Fn() = move || println!("Hello");
      |            ^^^^^^^^^
    

    "Но ждать!" вы говорите: «У меня есть такой тип в аргументе моей функции!». Правда в том, что нет.

    Этот синтаксис:

    fn foo(x: impl Fn()) {}
    

    Это просто сокращение для этого:

    fn foo<F>(x: F)
    where
        F: Fn(),
    {}
    

    Вы просто сконструировали дженерик и применили к нему привязанный трейт.

    Смотрите также:

    20.01.2019
    Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..