推断泛型类型的嵌套静态泛型函数

Java编译器能否从其上下文中推断泛型静态函数的类型作为另一个泛型静态函数的参数?

例如,我有一个简单的Pair类:

public class Pair<F, S> {

    private final F mFirst;

    private final S mSecond;

    public Pair(F first, S second) {
        mFirst  = checkNotNull(first);
        mSecond = checkNotNull(second);
    }

    public static <F, S, F1 extends F, S1 extends S> Pair<F, S> of(F1 first, S1 second) {
        return new Pair<F, S>(first, second);
    }

    public F first() {
        return mFirst;
    }

    public S second() {
        return mSecond;
    }

    // ...
}

我有以下通用静态函数:

public static <F, P extends Pair<F, ?>> Function<P, F> deferredFirst() {
    return (Function<P, F>)DEFERRED_FIRST;
}

private static final Function<Pair<Object, ?>, Object> DEFERRED_FIRST = 
        new Function<Pair<Object,?>, Object>() {

    @Override
    public Object apply(Pair<Object, ?> input) {
        return input.first();
    }
};

我想使用如下(Collections2.transform来自Google Guava):

List<Pair<Integer, Double>> values = ...
Collection<Integer> firsts = Collections2.transform(values, 
        Pair.deferredFirst());

编译器抱怨:

The method transform(Collection<F>, Function<? super F,T>) in the type 
Collections2 is not applicable for the arguments 
(List<Pair<Integer,Double>>, Function<Pair<Object,?>,Object>)

因此,编译器似乎无法将推断为transform()的类型传播给deferredFirst(),因为它认为它们是对象。

强制编译器通过以下任一方式了解类型:

Function<Pair<Integer, ?>, Integer> func = Pair.deferredFirst();
Collection<Integer> firsts = Collections2.transform(values, func);


Collection<Integer> firsts = Collections2.transform(values, 
        Pair.<Integer, Pair<Integer, ?>>deferredFirst());

是否可以更改函数的签名以允许编译器推断/传播类型?

编辑:对于波希米亚,这里有一个可能的方法,上面的例子可以用于:

public static int sumSomeInts(List<Pair<Integer, Double>> values) {
    Collection<Integer> ints = Collections2.transform(values, 
            Pair.deferredFirst());
    int sum = 0;
    for(int i : ints)
        sum += i;
    return sum;
}

类型推断是讨厌和复杂的。 他们必须在某个地方停下来。 考虑

static <T> T foo();

String s = foo();

print( foo() )

在赋值语境中,程序员的意图很明确, T应该是String

在下一行中,不是那么多。

print方法不是一个很好的例子,它严重超载。 假设print不重载,它的参数类型是固定的,所以T可以被清楚地推断出来。 编译器是否应该足够聪明以解决问题?

这听起来很合理,直到有人冒险阅读相关的规范文本,15.12方法调用表达式好运改变了这个混乱中的任何东西!

它太复杂了,即使编译器作者也不理解它。 javac和其他编译器中有大量的bug来源于这部分规范。


试试这个泛型功夫:

public static int sumSomeInts(List<Pair<Integer, Double>> values) {
    Collection<Integer> ints = Collections2.transform(values, 
        Pair.<Integer, Double>deferredFirst());
    int sum = 0;
    for(int i : ints)
        sum += i;
    return sum;
}

您可以键入方法调用并将泛型传递给下一个调用。

我不确定这里使用的确切泛型参数,因为您没有包含足够的代码。 如果你粘贴问题的整个方法,我将编辑这个答案,使其编译。 编辑:从问题的新信息

请让我知道它是否编译。 如果不是这个解决方案,它会很接近。 关键是使用Class.<Type>staticMethod()语法来输入静态方法。


我刚才提出的是:

@SuppressWarnings("rawtypes")
private static final Function ExtractFirst = new Function() {
    @Override
    public Object apply(final Object from) {
        Preconditions.checkNotNull(from);
        return ((Pair)from).first;
    }
};

@SuppressWarnings("unchecked")
public static <A> Function<Pair<A,?>,A> extractFirst() {
    return ExtractFirst;
}

不要让“SuppressWarnings”让你失望,它可以正常工作。

例:

List<Pair<String,String>> pairs = ImmutableList.of(Pair.of("a", "b"),
    Pair.of("c", "d"),Pair.of("e", "f"));
Iterable<String> firsts = Iterables.transform(pairs,
    Pair.<String>extractFirst());

不幸的是,是的,你必须提供extractFirst()的通用参数。 我认为这是你得到的最好的。

链接地址: http://www.djcxy.com/p/43149.html

上一篇: Inferring generic types of nested static generic functions

下一篇: Convincing GHC that `Maybe Void` is a unit type