【问题标题】:Why does this branch break type inference?为什么这个分支会破坏类型推断?
【发布时间】:2017-02-27 11:48:39
【问题描述】:

我在 Java 中使用 Either 的本土实现,它有这样的方法:

public static <L, R> Either<L, R> left(final L value);

public static <L, R> Either<L, R> right(final R value);

public <T> T fold(
        final Function<? super L, ? extends T> leftFunction,
        final Function<? super R, ? extends T> rightFunction); 

这两个方法编译和工作正常:

Either<Foo, Bar> rightToLeft() {
    Either<Foo, Bar> input = Either.right(new Bar());
    return input.fold(
        l -> null, 
        r -> Either.left(new Foo())
    );
}

Either<Foo, Bar> rightToRight() {
    Either<Foo, Bar> input = Either.right(new Bar());
    return input.fold(
        l -> null,
        r -> Either.right(new Bar())
    );
}

此方法无法编译:

Either<Foo, Bar> rightToLeftOrRightConditionally() {
    Either<Foo, Bar> input = Either.right(new Bar());
    return input.fold(
        l -> null, 
        r -> {
            if (r.equals("x")) {
               return Either.left(new Foo());
            }
            return Either.right(new Bar());
        });
}

错误:

incompatible types: inferred type does not conform to upper bound(s)
    inferred: Either<? extends Object,? extends Object>
    upper bound(s): Either<Foo,Bar>,java.lang.Object

(我已经删除了包限定符以使错误更具可读性)

我可以通过指定类型使其编译:

if (r.equals("x")) {
    return Either.<Foo, Bar> left(new Foo());
}
return Either.<Foo, Bar> right(new Bar());

但我为什么需要这样做?以及如何避免这种代码混乱?

【问题讨论】:

  • 因为编译器弄糊涂了?您应该发布 leftright 的代码
  • @RC。我添加了left()right() 的签名
  • 无法重现。在 javac 和 eclipse 中,这对我来说都很好。
  • @JornVernee 感谢您的关注。请参阅下面我对 Dmitri 的回复——您使用的是哪个版本的 javac
  • @Slim 我正在使用javac 1.8.0_101

标签: java type-inference


【解决方案1】:

这段代码应该可以工作。

它在最新的 JDK 1.8.0_121 上编译。

在 JDK 1.8.0-51 上编译失败。

这意味着它很可能是这个版本的 JDK 中的一个错误,因为以后的版本不应该改变编译器的行为,除非修复一个错误。可能是bugJDK-8055963

所以,解决方案是:

  1. 升级编译器
  2. 如果您无法升级编译器(例如,其他人、固执、拥有构建系统),请坚持使用现有的解决方法,使类型显式化。

【讨论】:

    【解决方案2】:

    我没有看到你的整个班级,但这段代码为我编译:

    class Foo{}
    class Bar{}
    
    class Either<L,R> {
    
        private L left;
        private R right;
    
        public Either(L left, R right) {
            this.left = left;
            this.right = right;
        }
    
        public static <L, R> Either<L,R> left(L l) {
            return new Either<>(l, null);
        }
    
        public static <L, R> Either<L,R> right(R r) {
            return new Either<>(null, r);
        }
    
    
        public <T> T fold(
                final Function<? super L, ? extends T> leftFunction,
                final Function<? super R, ? extends T> rightFunction) {
            return null;
        }
    
        Either<Foo, Bar> rightToLeft() {
            Either<Foo, Bar> input = Either.right(new Bar());
            return input.fold(
                    l -> null,
                    r -> Either.left(new Foo())
            );
        }
    
        Either<Foo, Bar> rightToRight() {
            Either<Foo, Bar> input = Either.right(new Bar());
            return input.fold(
                    l -> null,
                    r -> Either.right(new Bar())
            );
        }
    
        Either<Foo, Bar> rightToLeftOrRightConditionally() {
            Either<Foo, Bar> input = Either.right(new Bar());
            return input.fold(l -> null, r -> {
                if (r.equals("x")) {
                    return Either.left(new Foo());
                }
                return Either.right(new Bar());
            });
        }
    }
    

    【讨论】:

    • 我将其复制/粘贴到test.java,将import java.util.function.Function 添加到您的版本中,运行javac test.java 并得到inferred type does not conform to upper bound(s)。 Javac 版本javac 1.8.0_51.
    • 哈!在 JDK 1.8.0_121 中编译,但在 JDK 1.8.0_51 中不编译——想知道哪个错误修复负责。
    • 我在考虑 Java 版本(7 与 8)之间的差异,但它已在 Java 8 版本中得到修复。有趣。
    猜你喜欢
    • 2021-09-09
    • 1970-01-01
    • 2013-02-03
    • 1970-01-01
    • 1970-01-01
    • 2016-08-16
    • 1970-01-01
    • 1970-01-01
    • 2021-08-15
    相关资源
    最近更新 更多