在Java中模拟求和类型的巧妙解决方法

在继续阅读实际文章之前,我想感谢令人敬畏的Javaslang库的作者Daniel Dietrich ,他在我面前有了这个主意:

逆变通用界

这一切都始于一条推文:

我想做一些事情,像模式匹配一​​组类型的普通超级类型,方法如下:

<T super T1 | T2 | ... | TN>

请注意,我真正想要的是对联合类型的支持,而不是我最初声称的交集类型。

我为什么要这么做? 因为它将很好地添加到jOOλ库中 ,该具有Java的类型安全元组

class Tuple3<T1, T2, T3> {
    final T1 v1;
    final T2 v2;
    final T3 v3;

    // Lots of useful stuff here
}

在元组中最好的是迭代所有属性的forEach()方法:

tuple(1, "a", null).forEach(System.out::println);

上面将简单地产生:

1
"a"
null

现在,此forEach()方法的参数类型是什么? 它看起来像这样:

class Tuple3<T1, T2, T3> {
    void forEach(Consumer<? super T1 | T2 | T3> c) {}
}

消费者将收到类型为T1 T2 T3的对象。 但是接受前面三种类型的普通超级类型的消费者也可以。 例如,如果我们有:

Tuple2<Integer, Long> tuple = tuple(1, 2L);
tuple.forEach(v->System.out.println(v.doubleValue()));

上面的代码可以编译,因为NumberIntegerLong的常见超级类型,并且它包含doubleValue()方法。

不幸的是,这在Java中是不可能的

Java当前仅对异常捕获块支持联合/求和类型( 另请参见代数数据类型 ),您可以在其中编写以下内容:

class X extends RuntimeException {
    void print() {}
}
class X1 extends X {}
class X2 extends X {}

// With the above
try {
    ...
}
catch (X1 | X2 e) {
    // This compiles for the same reasons!
    e.print();
}

但是不幸的是,catch块是Java中唯一允许使用求和类型的位置。

这是Daniel巧妙而狡猾的解决方法发挥作用的地方。 我们可以编写一个静态方法来使用泛型执行某种“模式匹配”(如果您斜视),反之亦然:

static <
    T, 
    T1 extends T, 
    T2 extends T, 
    T3 extends T
> 
void forEach(
    Tuple3<T1, T2, T3> tuple, 
    Consumer<? super T> consumer
) {
    consumer.accept(tuple.v1);
    consumer.accept(tuple.v2);
    consumer.accept(tuple.v3);
}

现在可以安全地使用以上方法来推断T1,T2和T3的公共超级类型:

Tuple2<Integer, Long> t = tuple(1, 2L);
forEach(t, c -> {
    System.out.println(c.doubleValue());
});

符合预期:

1.0
2.0

这是有道理的,因为泛型类型约束是简单地“相反地”指定的,即,当T1 extends T强制T1 extends T ,强制是T super T1

如果你真的很quin眼;-)

据说Daniel在Javaslang即将推出的模式匹配API中使用了此技术。 我们期待看到这一结果!

翻译自: https://www.javacodegeeks.com/2016/02/ingenious-workaround-emulate-sum-types-java.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值