io.vavr.control.Validation如何在这些示例中起作用?

And*_*ong 2 java generics validation currying vavr

我在理解验证库时遇到了一些麻烦io.vavr.control.Validation.有可能提出过于宽泛的问题,我确实有几个子问题 - 但我相信它们是密切相关的,并且会拼凑起来帮助我理解使用这种验证机制的正确方法.

我从这里的例子开始:https://softwaremill.com/javaslang-data-validation.

Validation<String, ValidRegistrationRequest> validate(RegistrationRequest request) {
   return combine(
       validateCardId(request.getCardId()),
       validateTicketType(request.getTicketType()),
       validateGuestId(request.getGuestId())
)
       .ap(ValidRegistrationRequest::new)
       .mapError(this::errorsAsJson);
}

private Validation<String, Card> validateCardId(String cardId) {
    // validate cardId
    // if correct then return an instance of entity the cardId corresponds to
}

private Validation<String, TicketType> validateTicketType(String ticketType) {
    // validate ticketType
    // if known then return enumeration representing the ticket
}

private Validation<String, Guest> validateGuest(String guestId) {
    // validate guestId
    // if correct then return an instance of entity the questId corresponds to
}
Run Code Online (Sandbox Code Playgroud)

起初,我不明白通用参数的Validation<String, ValidRegistrationRequest>来源.我现在明白它们分别链接到传递给mapError和的方法的返回类型ap.但:

  1. 怎么combine知道返回Validation<String, ValidRegistrationRequest>?我觉得这是可能的唯一方法,如果combine实际上是a Validation<String, ValidRegistrationRequest>::combine,那么从这个模板中定义apmapError.但我不相信编译器应该能够暗示这是combine指返回类型的类中的静态实现.这里发生了什么事?

  2. [Minor]使用a的用例是什么ValidRegistrationRequest,而不是RegistrationRequest再次使用?在我的编码中,我很想做后者,直到我看到一个例子.

我正在阅读的第二个例子是:http://www.vavr.io/vavr-docs/#_validation.

class PersonValidator {

    private static final String VALID_NAME_CHARS = "[a-zA-Z ]";
    private static final int MIN_AGE = 0;

    public Validation<Seq<String>, Person> validatePerson(String name, int age) {
        return Validation.combine(validateName(name), validateAge(age)).ap(Person::new);
    }

    private Validation<String, String> validateName(String name) {
        return CharSeq.of(name).replaceAll(VALID_NAME_CHARS, "").transform(seq -> seq.isEmpty()
                ? Validation.valid(name)
                : Validation.invalid("Name contains invalid characters: '"
                + seq.distinct().sorted() + "'"));
    }

    private Validation<String, Integer> validateAge(int age) {
        return age < MIN_AGE
                ? Validation.invalid("Age must be at least " + MIN_AGE)
                : Validation.valid(age);
    }

}
Run Code Online (Sandbox Code Playgroud)
  1. Seq来自哪里?当没有mapError提供时,这是默认值吗?但我正在查看Validation.class的反编译.class文件,唯一的引用Seq是:

      static <E, T> Validation<List<E>, Seq<T>> sequence(Iterable<? extends Validation<List<E>, T>> values) {
        Objects.requireNonNull(values, "values is null");
        List<E> errors = List.empty();
        List<T> list = List.empty();
        Iterator var3 = values.iterator();
    
        while(var3.hasNext()) {
          Validation<List<E>, T> value = (Validation)var3.next();
          if (value.isInvalid()) {
            errors = errors.prependAll(((List)value.getError()).reverse());
          } else if (errors.isEmpty()) {
            list = list.prepend(value.get());
          }
        }
    
        return errors.isEmpty() ? valid(list.reverse()) : invalid(errors.reverse());
      }
    
    Run Code Online (Sandbox Code Playgroud)

    其中,我认为不相关.也许我用的是过时的Validation?(毕竟javaslang.control.Validation我的进口产品不是io.vavr.control.Validation.)

  2. 我对这两个例子都提出了这个问题:如何combine知道要传递给构造函数(ap)的参数以及按什么顺序?答案是"所有参数,按给定的顺序"?

提前致谢.

Mic*_*arz 9

在第一次寻找Vavr的验证机制时,你有同样的疑问和疑问.

以下是我对前两个问题的回答:

  1. combine(...)方法返回一个验证构建器的实例,在这种情况下,这是一个包含Builder3三个validate*(...)函数结果的类.该ap(...)方法是此构建器的方法,并触发Validation实例的构建.

调用它时,验证结果将逐个应用于作为参数提供的函数的curried版本:

v3.ap(v2.ap(v1.ap(Validation.valid(f.curried()))))
Run Code Online (Sandbox Code Playgroud)

在示例中,fValidRegistrationRequest类的构造函数.最后,我们有一个持有有效请求实例的验证.

另一方面,如果任何结果无效,则该方法会使用错误消息列表创建无效结果.并且调用mapError(this::errorsAsJson)(Validation例如这次!)将其转换为JSON格式.

  1. 使用的用例是ValidRegistrationRequest什么?

我在我的一个项目中使用了Vavr的验证.我有一个请求带有一些实体标识符.为了验证它的正确性,我不得不查询数据库以检查每个id是否有东西.

因此,如果验证与原始请求一起返回,我将不得不再次从数据库中获取这些对象.因此,我决定返回ValidRegistrationRequest持有域对象.仅调用一次数据库,请求处理速度明显加快.

并回答第二对问题:

  1. 是的,你是对的.如果结果无效,则Validation.combine(...).ap(...)返回带有实例的Invalid类,其中包含从验证方法返回的错误消息列表.

如果您查看源代码,Validation.ap(...)方法,您可以看到无效结果被收集到Vavr中List.因为它继承自Seq,所以您可以在validatePerson示例中看到此类型Seq<String>.

  1. 对,就是这样."所有参数,按给定的顺序":)

参数的顺序combine必须与提供给ap(...)方法的函数所采用的参数顺序相同.

通过下载源代码,可以更轻松地跟踪Vavr的内部.