Использование немономорфизируемых универсальных параметров в функции

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

В частности, я хочу применить функцию из PartialOrd к подмножеству случаев из данного перечисления. Вот базовая версия того, что я пытаюсь реализовать:

enum Value {
    String(String),
    Float(f64),
    Array(Vec<Value>),
}

fn apply_op<T, F>(v: &Value, compare_val: &Value, op: F) -> bool
where
    F: FnOnce(&T, &T) -> bool,
    T: PartialOrd,
{
    match (v, compare_val) {
        (Value::String(s), Value::String(compare_str)) => op(s, compare_str),
        (Value::Float(f), Value::Float(compare_f)) => op(f, compare_f),
        _ => false,
    }
}

А затем что-то вроде PartialOrd::gt заменяется на op.

Поскольку тип T определяется плечом сопоставления, он не может быть мономорфизирован и, следовательно, не будет компилироваться.

Есть ли способ обойти это, может быть, с какой-то структурой черты/обертки?

Ссылка на игровую площадку здесь, который включает в себя версию выше (которая не компилируется) и подход к макросам, который я сейчас использую, чтобы обойти это. Макрос работает нормально, но кажется, что это должно быть возможно и без него.

Похоже на ту же проблему здесь. Макрос — единственный способ сделать это в настоящее время, поскольку HKT в настоящее время недоступны в Rust.

Ian S. 17.05.2022 21:45
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Четыре эффективных способа центрирования блочных элементов в CSS
Четыре эффективных способа центрирования блочных элементов в CSS
У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то...
0
1
38
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы не можете поздно связать универсальную функцию, но вы можете создать для нее трейт:

pub trait Comparator<T> {
    fn compare(self, a: &T, b: &T) -> bool;
}

Затем создайте тип для каждого компаратора, например Gt:

struct Gt;
// You can also implement it individually for `String`, `f64` and `Vec<Value>`.
impl<T: PartialOrd> Comparator<T> for Gt {
    fn compare(self, a: &T, b: &T) -> bool {
        PartialOrd::gt(a, b)
    }
}

Затем:

fn apply_op<F>(v: &Value, compare_val: &Value, op: F) -> bool
where
    F: Comparator<String> + Comparator<f64> + Comparator<Vec<Value>>,
{
    match (v, compare_val) {
        (Value::String(s), Value::String(compare_str)) => op.compare(s, compare_str),
        (Value::Float(f), Value::Float(compare_f)) => op.compare(f, compare_f),
        _ => false,
    }
}

Это был ключ! Для потомков, в основном, вот как я это реализовал (используя существующее перечисление Op вместо трейта): детская площадка. Огромное спасибо!

erik rhodes 17.05.2022 22:43

@erikrhodes Обратите внимание, что рука _ => return false избыточна, поскольку другие руки уже полностью соответствуют перечислению. (Я бы даже сказал, что рука вредна, как если бы вы позже гипотетически добавили новый вариант перечисления, вы бы хотеть ошибались во время компиляции, которую вы не обработали.)

cdhowie 17.05.2022 22:54

@cdhowie Отличное замечание - это намеренно сделано в моем реальном коде, где есть другие варианты, которые не соответствуют реализациям PartialOrd, но здесь совершенно не нужны. Думаю, здесь правильнее всего вернуть Result и Err на неподдерживаемые спичечные плечи.

erik rhodes 17.05.2022 23:03

@erikrhodes Да, это имеет смысл, ИМО, поскольку позволяет звонящему решить, паниковать или нет.

cdhowie 18.05.2022 04:42

Другие вопросы по теме