java object转list_十分钟魔法练习:高阶类型(Java)

a593b5d13dd303e53c6a7de2f62dfc42.png
前置技能:Java基础
文章来源:goldimax/magic-in-ten-mins (求Star QAQ)

常常碰到的困难

写代码的时候常常会碰到语言表达能力不足的问题,比如下面这段用来给F容器中的值进行映射的代码:

interface Functor<F> {
    <A, B>
    F<B> map(F<A> a, Function<A, B> f);
}

并不能通过javac的编译,编译器会告诉你F不能有泛型参数。

最简单粗暴的解决方案就是放弃类型检查,全上Object,如:

interface Functor<F> {
    Object map(Object a, 
               Function<Object, Object> f);
}

实际上Java经常这么干,标准库中到处是Object的身影,重载的各种接口也常常要手工转换类型,equals要和Object比较,compareTo要和Object比较……似乎习惯了以后也挺好,又不是不能用!

高阶类型

假设类型的类型是Type,比如intString类型都是Type

而对于List这样带有一个泛型参数的类型来说,它相当于一个把类型T映射到List<T>的函数,其类型可以表示为Type -> Type

同样的对于Map来说它有两个泛型参数,类型可以表示为(Type, Type) -> Type

像这样把类型映射到类型的非平凡类型就叫高阶类型(HKT, Higher Kinded Type)。

虽然Java中存在这样的高阶类型但是我们并不能用一个泛型参数表示出来,也就不能写出如上F<A>这样的代码了,因为F是个高阶类型。

如果加一层解决不了问题,那就加两层。

虽然在Java中不能直接表示出高阶类型,但是我们可以通过加一个中间层来在保留完整信息的情况下强类型地模拟出高阶类型。

首先,我们需要一个中间层:

interface HKT<F, A> {}

然后我们就可以用HKT<F, A>来表示F<A>,这样操作完HKT<F, A>后我们仍然有完整的类型信息来还原F<A>的类型。

这样,上面Functor就可以写成:

interface Functor<F> {
    <A, B> 
    HKT<F, B> map(HKT<F, A> ma, 
                  Function<A, B> f);
}

这样就可以编译通过了。而对于想实现Functor的类,需要先实现HKT这个中间层,这里拿List举例:

class HKTList<A> 
    implements HKT<HKTList<?>, A> {
    
    List<A> value;
    
    HKTList() {
        value = new ArrayList<>();
    }
    
    HKTList(List<A> v) {
        value = v;
    }
    
    static <T> HKTList<T>
    narrow(HKT<HKTList<?>, T> v) {
        return (HKTList<T>) v;
    }
    
    static <T> Collector<T, ?, HKTList<T>>
    collector() { /* ... */ }
}

注意HKTList把自己作为了HKT的第一个参数来保存自己的类型信息,这样对于HKT<HKTList<?>, T>这个接口来说就只有自己这一个子类,而在narrow函数中可以安全地把这个唯一子类转换回来。

这样,实现Functor类就是一件简单的事情了:

class ListF 
    implements Functor<HKTList<?>> {
    
    public <A, B> HKT<HKTList<?>, B>
    map(HKT<HKTList<?>, A> ma, 
        Function<A, B> f) {
        
        return HKTList.narrow(ma)
            .value.stream().map(f)
            .collect(HKTList.collector());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值