【问题标题】:Composing function with identity function yields type mismatch用恒等函数组合函数会产生类型不匹配
【发布时间】:2016-06-29 02:34:46
【问题描述】:

我有一个enum 和一个为enum 值生成自定义字符串转换函数的方法:

public enum MyEnum {
  DUMMY;
}

public <E extends Enum<E>> Function<E, String> stringify(String suffix) {
  return enumValue -> enumValue.name() + suffix;
}

我想使用该方法为我的特定枚举类型制作一个函数:

public void test() {
  Function<MyEnum, String> f = stringify("");
}

这行得通,但我还需要我的函数对字符串进行一些后续处理。举例来说,假设后续处理只是恒等函数:

public void test() {
  Function<MyEnum, String> f = stringify("").andThen(Function.identity());
}

现在我得到一个编译错误。 Eclipse(霓虹灯) 说:

类型不匹配:无法从 Function&lt;Enum&lt;Enum&lt;E&gt;&gt;,String&gt; 转换为 Function&lt;Test.MyEnum,String&gt;

javac 说:

error: incompatible types: no instance(s) of type variable(s) V,T#2 exist so that Function<E,V> conforms to Function<MyEnum,String>
        Function<MyEnum, String> f = stringify("").andThen(Function.identity());
                                                      ^
  where V,R,T#1,T#2,E are type-variables:
    V extends Object declared in method <V>andThen(Function<? super R,? extends V>)
    R extends Object declared in interface Function
    T#1 extends Object declared in interface Function
    T#2 extends Object declared in method <T#2>identity()
    E extends Enum<E>

Function.identity() 的返回类型与其参数类型相同,所以我看不出它如何将整体结果更改为 Function&lt;MyEnum, String&gt; 以外的其他值。 Eclipse 错误消息中的Enum&lt;Enum&lt;E&gt;&gt; 让我特别困惑。

我注意到我可以通过将中间结果分配给一个变量来避免这个问题:

public void test() {
  Function<MyEnum, String> f1 = stringify("");
  Function<MyEnum, String> f2 = f1.andThen(Function.identity());
}

但如果可能的话,我宁愿避免这种情况。

为什么会出现这种类型不匹配?最好的解决方法是什么?

【问题讨论】:

    标签: java generics enums functional-programming


    【解决方案1】:

    这是一个泛型边界问题。

    在此声明中:

    Function<MyEnum, String> f = stringify("").andThen(Function.identity());
    

    编译器不知道 stringify("") 的界限,因此也无法推断 Function.identity() 的界限。

    要解决此问题,您需要为stringify("") 添加绑定:

    Function<MyEnum, String> f = this.<MyEnum>stringify("").andThen(Function.identity());
    

    注意this 关键字也被添加,因为你不能简单地写&lt;MyEnum&gt;stringify("")

    如果 stringify("") 方法来自某个静态 util 类,则它将如下所示:

    Function<MyEnum, String> f = MyUtils.<MyEnum>stringify("").andThen(Function.identity());
    

    【讨论】:

    • 如果没有andThen 调用,编译器就知道stringify("") 的类型边界,因为它来自f 的声明类型。通过andThen 调用,stringify("") 的结果不再直接分配给f,但我认为编译器会认识到进入andThen 的类型必须与来自andThen 的类型相同它。但听起来你是在说类型推断不能像那样向后工作。
    • 我可能让你有点困惑。从.andThen 的角度推断的类型,当没有明确地与类型绑定时,实际上是&lt;? extends Enum&lt;?&gt;&gt;。这正是您在 stringify 方法中定义的内容。因此,在您的问题中,您实际上是将 Function&lt;? extends Enum&lt;?&gt;, String&gt; 分配给了 Function&lt;MyEnum, String&gt;,这是不允许的。
    猜你喜欢
    • 1970-01-01
    • 2016-10-24
    • 2018-04-27
    • 1970-01-01
    • 1970-01-01
    • 2021-01-20
    • 2022-08-18
    • 1970-01-01
    • 2013-05-04
    相关资源
    最近更新 更多