Несовместимые типы при использовании вложенных групповых символов с верхним ограничением - PullRequest
2 голосов
/ 16 апреля 2020

Я работаю над библиотекой функционального программирования для Java и столкнулся с неприятной проблемой. В моем классе Option<V> есть следующие функции:

/**
 * Returns an Option containing the provided value.
 */
public static <V> Option<V> some(V value)
{...}

/**
 * Returns an Option that contains nothing.
 */
public static <V> Option<V> none()
{...}

/**
 * Decide control flow based on whether this is Some or None,
 * returning the result of the chosen operation.
 *
 * @param some the operation to perform on the contained value if there is one
 * @param none the operation to perform if there is no contained value
 * @return the result of the matched operation
 */
public <T> T matchThen(Function<? super V, ? extends T> some, Supplier<? extends T> none)
{...}

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

/**
 * Returns this if it is a Some, otherwise computes an Option from the given Supplier.
 * @param supp the supplier to compute the other Option
 * @return the first present value or None
 */
public Option<V> orElse(Supplier<? extends Option<? extends V>> supp)
{
    return matchThen(
            Option::some, // if there is a value, wrap it back up and return it
            supp::get     // if there isn't a value, get one from the supplier
    );
}

IDEA сообщает об ошибке с использованием Option::some в orElse:

Неверный тип возврата в ссылке на метод: невозможно преобразовать Option<V> в ? extends Option<? extends V>

Мое понимание подстановочных знаков заключалось в том, что Option<? extends V> принимает любой объект типа Option<T>, где <T extends V>, что означало бы, что Option<V> определенно является Option<? extends V>. Аналогично, Я бы ожидал , что параметр типа ? extends Option<? extends V> примет то же самое (Option<T>, как указано выше или Option<V>).

Итак, у меня есть два вопроса :

  1. Почему происходит эта ошибка? Я ожидал, что это будет случай , где ? extends Type<? extends V> работает. В этом случае мои ожидания неверно применяются? Я вижу, как я мог неправильно истолковать ошибку, так как задействовано несколько типов, и я признаю, что не уверен, что мой приведенный выше анализ верен.
  2. Есть ли исправление сигнатур методов, которое не жертвуете гибкостью или делает это минимально? Я бы хотел, чтобы пользователи этой библиотеки не беспокоились о реально совместимых значениях и функциях, вызывающих ошибки типов из-за моего API.

Примечание

Я не спрашиваю для реализации orElse, которая избегает этой ошибки типа; У меня уже есть инструмент для этого, и мне все равно, использует ли моя реализация незначительные обходные пути. Мое главное беспокойство заключается в том, что пользователи этой библиотеки могут столкнуться с проблемой такого типа при реализации своих собственных решений, поэтому я хочу сделать эти методы максимально гибкими для типов, поэтому я в первую очередь использую все эти шаблоны.

1 Ответ

2 голосов
/ 16 апреля 2020

Ааа, вложенные символы подстановки.

Не ведите себя так, как вы ожидаете. Быстрый поиск дает Несколько групповых символов для обобщенных c методов, что делает Java компилятор (и меня!) Очень запутанным в качестве кандидата на канонический ответ.

Фактически вы пытаетесь получить тип, возвращаемый supp.get() (Option<? extends V>), который будет возвращен orElse (Option<V>), чего не происходит.

Предположительно Интерфейс для Option использует только V в роли продюсера, но нет способа выразить это в Java.

. Было бы легко исправить тип возвращаемого значения Option<? extends V>.

Вы можете сохранить более приятный интерфейс, заменив второй аргумент matchThen лямбда-функцией, которая разворачивает Supplier и Option<? extends V> в прямую ссылку V, а затем перематывается как Option<V>.

...