Сопоставление с образцом соответствует всем условиям случая

Я новичок в vavr, поэтому я не знаю, пропускаю ли я какие-то базовые вещи, но я выполняю сопоставление с образцом, которого сейчас нет в Java. После отладки я понял, что vavr соответствует всем случаям, но не будет выполнять значение, если указан поставщик, если условие случая не соответствует. Это правильно?

например:

public Enum Days{
    MONDAY,
    TUESDAY...
}

String s = Match(days).of(
        Case($(Days.MONDAY), "monday"),
        Case($(Days.TUESDAY), "tuesday")
);

В приведенном выше примере, если days = MONDAY, он вызывает метод CASE, передает значение перечисления и проверяет, есть ли совпадение. В этом случае это совпадение, поэтому он вернет «понедельник». Я надеялся, что сопоставление с образцом будет прекращено, так как мы получили совпадение. Но оказывается, что он снова входит в метод Case для вторника, шаблон не совпадает, поэтому значение остается «понедельник», но мне было интересно, есть ли способ остановить сопоставление шаблона после выполнения условия.


person Sachin Jain    schedule 02.05.2019    source источник


Ответы (2)


Vavr Match остановится на первом совпадении Case и вернет соответствующее значение.

То, что вы испытываете, - это просто стандартное поведение Java. Аргументы тщательно обрабатываются перед передачей в метод, поэтому, когда вы пишете

Case(Pattern, retValExpression)

а retValExpression является выражением, выражение retValExpression будет нетерпеливо оцениваться еще до того, как оно будет передано методу фабрики API.Case. Если вы хотите, чтобы выражение retValExpression оценивалось лениво только при совпадении Case, вам нужно преобразовать его в Supplier, создав лямбда-выражение:

Case(Pattern, () -> retValExpression)

В этом случае лямбда-выражение () -> retValExpression будет оцениваться только при совпадении соответствующего Case.

Если ваша проблема заключается в том, что выражения Pattern вычисляются с нетерпением, вы можете применить тот же метод, чтобы преобразовать их в ленивые вычисления, указав лямбда-выражение для Predicate:

Case($(value -> test(value)), () -> retValExpression)
person Nándor Előd Fekete    schedule 02.05.2019
comment
Привет, Нандор, я сделал это, я предоставил поставщика, и это сработало, и да () -> retValExpression оценивается только при совпадении случая. Но мой вопрос был в другом. Я хотел спросить, скажем, даже если у нас есть Поставщик в качестве значения для всех случаев, он все равно проверяет, есть ли совпадение, даже если совпадение было найдено. Таким образом, он не будет выполнять поставщика, если совпадение не найдено, но по-прежнему вызывает метод Case для проверки каждого совпадения, даже если он будет выполнять значение только для совпадения, поскольку он является поставщиком. Надеюсь, мой вопрос имеет смысл - person Sachin Jain; 03.05.2019
comment
Это действительно не имеет смысла для меня. Возможно, у вас есть такая же проблема с нетерпеливой оценкой выражений Pattern, с помощью которых вы создаете значения Case. Если да, то происходит то же самое, что я описал в своем ответе, только в другом месте. Match.of остановится на первом совпадении, я только что посмотрел его в исходном коде. См. соответствующий исходный код. - person Nándor Előd Fekete; 03.05.2019
comment
Я обновил свой ответ, чтобы показать пример выражений шаблонов, которые лениво оцениваются, если это помогает. - person Nándor Előd Fekete; 03.05.2019

Я не согласен: как только кейс совпадает, он перестает оценивать другие кейсы, предполагая, что вы пишете свои кейсы в ленивом режиме (например, с предикатами и поставщиками). Проблема возникает из-за того, что Java по умолчанию стремится к оценке своих аргументов, это не имеет ничего общего с Vavr.

Вот контрпример того, что вы утверждаете. Пожалуйста, обрати внимание:

  • сопоставители ленивы (написаны с помощью Predicate)
  • значения ленивы (написаны с Поставщиком)

.

public class Main {
  public static void main(String[] args) {
    var result = Match("foo").of(
        Case($(choice("one")), () -> result("1")),
        Case($(choice("two")), () -> result("2"))
    );

    System.out.println(result);
  }

  static Predicate<String> choice(String choice) {
    return string -> {
      System.out.println("Inside predicate " + choice);
      return true;
    };
  }

  static String result(String result) {
    System.out.println("Inside result " + result);
    return result;
  }
}

При выполнении это дает:

Внутри предиката один

Внутренний результат 1

1

Обратите внимание, что ни второй предикат, ни второй результат никогда не оценивались.

person Sir4ur0n    schedule 02.05.2019
comment
Понял, спасибо, я тоже сделаю Cases Lazy, похоже, это сработает - person Sachin Jain; 03.05.2019