java - Java'reduceLeft'签名/下限类型参数

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

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

但是,由于>:是爪哇中的super的Scala等价物,所以我的第一个想法是转换这个签名(用BiFunction替换函数类型并使用使用站点方差注释AKA有界通配符)。
interface Collection<A> {
    <B super A> B reduceLeft(BiFunction<? super B, ? super A, ? extends B> mapper)
}

但是哦不!编译器抱怨super中的<B super A>标记,因为您不能有下界类型变量!现在,我如何在Java代码中编写这个方法,而不必在Java世界中不存在泛型时返回时间呢?
是的,我知道您认为我可以使用B extends A,但这与我的实现不同:
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;
}

相反,我不得不使用这个稍微受限的版本:
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;
}

最佳答案

scala方法定义中的B >: A约束是必需的,因为:
scala使用声明站点方差,不可变集合在它们包含的元素类型中是协变的。
reduceLeft在概念上需要返回类型为A的值,但使用A作为返回类型意味着在协变位置使用它,这与已声明的方差冲突,即A必须是协变的。
解决这种差异冲突的诀窍是引入B泛型类型。
现在,正如您所提到的,Java使用了使用站点的差异,所以用Java编写的任何集合都是不变的。这也意味着使用A作为方法的返回类型没有问题,即在相反的位置。因此,下面的定义应该足够了-不需要B类型:

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

但是,正如您所看到的,将A设为一个下界然后设为一个上界的净效果是,A基本上是不变的——如果不使用下转换,就不可能从通配符边界中获益。这意味着我们可以简化签名(这与Stream.reduce非常相似):
interface Collection<A> {
  A reduceLeft(BiFunction<A, A, A> reducer);
}

另外,类型BiFunction<A, A, A>已经在Java 8中以名为“AA>”出现。

本文翻译自 https://stackoverflow.com/questions/31418970/

网站遵循 CC BY-SA 4.0 协议,转载或引用请注明出处。

标签 java scala bounded-wildcard type-variables


相关文章:

java - Spring JPA / Hibernate org.hibernate.AssertionFailure:实体中的id为null(发生异常后不要刷新Session)

java - 使用SpEL表达式和PropertyPlaceHolder设置Spring bean类名

java - 文件上传和进度栏

algorithm - 将循环缓冲区复制到更大的缓冲区,同时保留内容和模数索引

java - 哪种方法声明接受有界和无界的多级泛型?

java - Java TLS 1.2相互认证以超时结束

java - 带有继承和mixins的Scala可测试代码

scala - 我可以在Apache Spark中捕获Executor启动等事件吗?

java - 使用下界通配符(Java)的“意外令牌”

java - 在Java中,常规泛型不能做外卡吗?