Обтекание контравариантного функционального интерфейса без потери общей

Я согласен с Берги в использовании Date, но его решение было немного излишним для моего использования. Я просто хотел, чтобы мои анимированные часы (цифровые и аналоговые SVG) обновлялись на втором и не переполнялись или выполнялись, создавая очевидные скачки в обновлениях часов. Вот фрагмент кода, который я ввел в мои функции обновления часов:

    var milliseconds = now.getMilliseconds();
    var newTimeout = 1000 - milliseconds;
    this.timeoutVariable = setTimeout((function(thisObj) { return function() { thisObj.update(); } })(this), newTimeout);

Он просто вычисляет время дельта до следующего даже второго и устанавливает тайм-аут этой дельта. Это синхронизирует все мои объекты часов со вторым. Надеюсь, это полезно.

4
задан Henning Makholm 13 July 2018 в 19:49
поделиться

3 ответа

Попробуйте этот странный трюк:

g = oa -> Math.max(0, f.apply(oa.map(a -> a)));
                             // ^----------^

Сопоставление типа необязательного, как это, позволяет компилятору «отличать» тип необязательного до согласованного типа.

Идеальная демонстрация

Это имеет недостаток в создании нового экземпляра Optional.


Но, конечно, я задал этот вопрос , который размышляет, действительно ли это то, что должно быть разрешено спецификацией или ошибкой.


Лично я не считаю ваше «лучшее до сих пор» особенно вопиющим. Конечно, это зависит от того, как выглядит реальный код.

2
ответ дан Andy Turner 17 August 2018 в 12:12
поделиться
  • 1
    Ах, я должен был использовать этот хак раньше; но это возможно только из-за API, который предоставляет Optional. В случаях, когда у нас нет API-интерфейса преобразования, я задаюсь вопросом, существует ли более общий шаблон;) – flakes 14 July 2018 в 02:08

Решение изменит вашу сигнатуру вашего интерфейса:

double apply(Optional<? extends A> a);

Анализ

Рассмотрим, если ваш интерфейс просто:

double apply(A a);

Тогда никогда ошибка не будет [. g3]

Это потому, что Double назначается Object. Компилятор автоматически адаптирует тип. Это означает, что на самом деле интерфейс:

double apply(? extends A a);

Итак, что вам нужно, это позволить вашему интерфейсу использовать эту способность адаптации.

func(Number) может принимать параметр Double в качестве параметра.

func(Optional<Number>) также должен принять Optional<Double>.

Итак, вы должны добавить ? extends на свою интуицию.

0
ответ дан Dean Xu 17 August 2018 в 12:12
поделиться

В общем, я нахожу, что вывод типа для суперграфов в Java является кошмаром. Есть много ошибок компилятора, и обычно трудно объяснить, почему компилятор отклонит определенный синтаксис, а не другие.

Тем не менее, вы можете обойти это хакерским способом, добавив f в тип Func<Double>. Это не совсем безопасный бросок; если f имеет какое-либо состояние, мы можем предположить, что нижняя граница на f равна Double, когда на самом деле это может быть Number или Object. С броском вы не несете штраф за выполнение решения, предоставленного @AndyTurner, но неконтролируемые роли также не являются вашим другом.

public double compute(Func<? super Double> f) {
    // Sometimes amend the function to do something slightly different
    Func<? super Double> g = f;
    if (someCondition())
        g = oa -> Math.max(0, (((Func<Double>) f)).apply(oa));

    return g.apply(Optional.of(3.14)) + g.apply(Optional.empty());
}

В целом, я бы рассмотрел решение, которое вы представили в вопросе быть лучшим решением проблемы. Это немного более подробный, но компилятор должен иметь возможность оптимизировать код. Вы не теряете безопасность времени компиляции с помощью непроверенных бросков, и вы не вводите дефрагментацию времени выполнения из-за создания дополнительных экземпляров Optional.

1
ответ дан flakes 17 August 2018 в 12:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: