最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Java'reduceLeft'签名下界类型参数

SEO心得admin84浏览0评论
本文介绍了Java'reduceLeft'签名/下界类型参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

以下签名有效,并在Scala中常用:

The following signature is valid and commonly used in Scala:

trait Collection[A] { def reduceLeft [B >: A] (f: (B, A) => B): B }

但是,由于>:是Java中 super 的Scala等价物,这是我的第一个想法转换此签名(将功能类型替换为 BiFunction 并使用Use-Site方差注释(也称为有界通配符))将是

However, since >: is the Scala equivalent of super in Java, my first idea to convert this signature (replacing the function type with BiFunction and making use of Use-Site variance annotations aka Bounded Wildcards) would be

interface Collection<A> { <B super A> B reduceLeft(BiFunction<? super B, ? super A, ? extends B> mapper) }

但是哦不!编译器抱怨< B超级A> 中的 super 令牌,因为您不能使用下界类型变数!现在,我该如何用Java代码编写此方法,而无需回到Java世界中不存在泛型的时间?

But oh no! The compiler complains about the super token in <B super A> because you can't have lower-bounded type variables! Now how would I write this method in Java code without having to time-travel back to when generics didn't exist in the Java world?

是的,我知道您认为我可以使用 B扩展A ,但这不是同一件事,如我的实现所示:

Yes, I know that you think I could use B extends A, but that is not the same thing, as shown by my implementation:

public <R extends E> R reduceLeft(BiFunction<? super R, ? super E, ? extends R> mapper) { if (this.isEmpty()) { return null; } Iterator<E> iterator = this.iterator(); R first = iterator.next(); // doesn't work, but would if R was a super-type of E (R super E) while (iterator.hasNext()) { mapper.apply(first, iterator.next()); } return first; }

相反,我不得不使用受限制的版本:

Instead, I had to use this slightly more restricted version:

public E reduceLeft(BiFunction<? super E, ? super E, ? extends E> mapper) { if (this.isEmpty()) { return null; } Iterator<E> iterator = this.iterator(); E first = iterator.next(); while (iterator.hasNext()) { first = mapper.apply(first, iterator.next()); } return first; }

推荐答案

B>:Scala方法定义中的A 约束是必要的,因为:

The B >: A constraint in the Scala method definition is necessary because:

  • Scala使用声明位置方差和不可变集合在它们包含的元素类型上是协变。
  • reduceLeft 从概念上讲,需要返回类型为 A 的值,但是使用 A 作为返回类型意味着在协变位置使用它,这与已经声明的方差冲突,即 A 必须是协变的。
  • Scala uses declaration-site variance and the immutable collections are covariant in the type of the elements they contain.
  • reduceLeft needs to, conceptually, return values of type A, but using A as a return type means using it in a covariant position, which conflicts with the already declared variance, i.e., A must be covariant.
  • 解决此差异冲突的技巧是引入 B 泛型类型。

    The trick to work around this variance conflict is to introduce that B generic type.

    现在,正如您所提到的,Java使用了使用站点差异,因此任何用Java编写的集合都是不变的。这也意味着使用 A 作为方法的返回类型(即互变位置)没有问题。因此,下面的定义应该足够了-不需要 B 类型:

    Now, as you've mentioned, Java employs use-site variance, so any collection written in Java will be invariant. This also means that there's no problem using A as the return type of a method, i.e., in contravariant position. So, the definition below should be enough — no need for a B type:

    interface Collection<A> { A reduceLeft(BiFunction<? super A, ? super A, ? extends A> reducer); }

    但是,如您所见,拥有 A 曾经是一个下界,然后一个上限是 A 本质上是不变的-不使用通配符界限是不可能的垂头丧气。这意味着我们可以简化签名(这非常类似于 Stream.reduce ):

    However, as you can see, the net effect of having A once be a lower bound and then an upper bound is that A is basically invariant — it's impossible to benefit from the wildcard bounds without using downcasting. That means we can simplify the signature (which is pretty similar to Stream.reduce):

    interface Collection<A> { A reduceLeft(BiFunction<A, A, A> reducer); }

    此外,类型 BiFunction< A,A, A> 在Java 8中已经存在,名称为 BinaryOperator< A> 。

    Also, the type BiFunction<A, A, A>, is already present in Java 8 under the name BinaryOperator<A>.

    发布评论

    评论列表(0)

    1. 暂无评论