《Kotlin核心编程》 ——2.4.2 Unit类型:让函数调用皆为表达式

举报
华章计算机 发表于 2020/02/21 20:56:30 2020/02/21
【摘要】 本节书摘来自华章计算机《Kotlin核心编程》 —— 书中第2章,第2.4.2节,作者是水滴技术团队 。

2.4.2 Unit类型:让函数调用皆为表达式

之所以不能说Java中的函数调用皆是表达式,是因为存在特例void。众所周知,在Java中如果声明的函数没有返回值,那么它就需要用void来修饰。如:

void foo () {

    System.out.println("return nothing");

}

所以foo()就不具有值和类型信息,它就不能算作一个表达式。同时,这与函数式语言中的函数概念也存在冲突,在Kotlin、Scala这些语言中,函数在所有的情况下都具有返回类型,所以它们引入了Unit来替代Java中的void关键字。

void与Void

当你在描述void的时候,需要注意首字母的大小写,因为Java在语言层设计一个Void类。java.lang.Void类似java.lang.Integer,Integer是为了对基本类型int的实例进行装箱操作,Void的设计则是为了对应void。由于void表示没有返回值,所以Void并不能具有实例,它继承自Object。

如何理解Unit?其实它与int一样,都是一种类型,然而它不代表任何信息,用面向对象的术语来描述就是一个单例,它的实例只有一个,可写为()。

那么,Kotlin为什么要引入Unit呢?一个很大的原因是函数式编程侧重于组合,尤其是很多高阶函数,在源码实现的时候都是采用泛型来实现的。然而void在涉及泛型的情况下会存在问题。

我们先来看个例子,Java这门语言并不天然支持函数是头等公民,我们现在来尝试模拟出一种函数类型:

interface Function<Arg, Return> {

    Return apply(Arg arg);

}

Function<String, Integer> stringLength = new Function<String, Integer>() {

    public Integer apply(String arg) {

        return arg.length();

    }

};

int result = stringLength.apply("hello");

// 运行结果

5

看上去似乎没什么问题。我们再来改造下,这一次希望重新实现一个print方法。于是,难题出现了,Return的类型用什么来表示呢?可能你会想到void,但Java中是不能这么干的。无奈之下,我们只能把Return换成Void,即Function<String, Void>,由于Void没有实例,则返回一个null。这种做法严格意义上讲,相当丑陋。

Java 8实际解决办法是通过引入Action<T>这种函数式接口来解决问题,比如:

Consumer<T>,接收一个输入参数并且无返回的操作。

BiConsumer<T,U>,接收两个输入参数的操作,并且不返回任何结果。

ObjDoubleConsumer<T>,接收一个object类型和一个double类型的输入参数,无返回值。

ObjIntConsumer<T>,接收一个object类型和一个int类型的输入参数,无返回值。

ObjLongConsumer<T>,接收一个object类型和一个long类型的输入参数,无返回值。

……

虽然解决了问题,但这种方案不可避免地创造了大量的重复劳动,所以,最好的解决办法就是引入一个单例类型Unit,除了不代表任何意义的以外,它与其他常规类型并没有什么差别。


【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。