推断嵌套静态泛型函数的泛型类型
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;
}
Is the Java compiler able to infer the type of a generic static function from its context as the argument to another generic static function?
For example, I have a simple Pair class:
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;
}
// ...
}
And I have the following generic static function:
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();
}
};
Which I wish to use as follows (Collections2.transform is from Google Guava):
List<Pair<Integer, Double>> values = ...
Collection<Integer> firsts = Collections2.transform(values,
Pair.deferredFirst());
To which the compiler complains:
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>)
So it seems that the compiler fails to propagate the types inferred for transform() to deferredFirst() as it thinks they are Objects.
Forcing the compiler to understand the types in either of these ways works:
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());
Is it possible to change either function's signature to allow the compiler to infer/propagate the types?
Edit: For Bohemian, here's a possible method the above example could be used in:
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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

发布评论
评论(3)
试试这个泛型功夫:
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.
语法键入静态方法。
我不久前想到的是:
@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() 提供通用参数。我认为这是你能得到的最好的。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
类型推断是令人讨厌且复杂的。他们必须在某个地方停下来。考虑
在赋值上下文中,程序员的意图很明确,
T
应该是String
,在下一行,而不是那么多。
print 方法不是一个非常公平的例子,它严重重载。假设
print
没有被重载,它的参数类型是固定的,因此可以清楚地推断出T
。编译器不应该足够聪明来解决这个问题吗?这听起来很合理,直到有人冒险阅读相关规范文本, 15.12 方法调用表达式 祝你好运,改变混乱中的任何东西!
它太复杂了,连编译器作者都看不懂。 javac 和其他编译器中存在大量源于规范这一部分的错误。
Type inference is nasty and complicated. They have to stop somewhere. Consider
In the assignment context, the intention of the programmer is clear,
T
should beString
In the next line, not so much.
The
print
method is not a very fair example, it is heavily overloaded. Supposeprint
isn't overloaded, its parameter type is fixed, soT
can be clearly inferred. Shouldn't the compiler be smart enough to figure it out?That sounds reasonable, until one ventures to read the related spec text, 15.12 Method Invocation Expressions Good luck changing anything in that mess!
It is so complicated, not even the compiler authors understand it. There are tons of bugs in javac and other compilers that originated from this section of the spec.