Kotlin 核心编程 (33):基础语法 2.4.2

阅读数:1 2019 年 12 月 25 日 15:34

Kotlin核心编程(33):基础语法 2.4.2

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

内容简介
本书不是一本简单介绍 Kotlin 语法应用的图书,而是一部专注于帮助读者深入理解 Kotlin 的设计理念,指导读者实现 Kotlin 高层次开发的实战型著作。书中深入介绍了 Kotlin 的核心语言特性、设计模式、函数式编程、异步开发等内容,并以 Android 和 Web 两个平台为背景,演示了 Kotlin 的实战应用。
全书共 13 章,分为 4 个部分:
热身篇—Kotlin 基础(第 1~2 章),简单介绍了 Kotlin 设计哲学、生态及基础语法,其中包括 Kotlin 与 Scala、Java 之间的关联与对比,以及 Kotlin 的类型声明的特殊性、val 和 var 的使用、高阶函数的使用、面向表达式编程的使用、字符串的定义与操作等内容;
下水篇—Kotlin 核心(第 3~8 章),深入介绍了面向对象、代数数据类型、模式匹配、类型系统、Lambda、集合、多态、扩展、元编程等 Kotlin 开发核心知识,这是本书的重点,其中涉及很多开发者特别关心的问题,比如多继承问题、模式匹配问题、用代数数据类型抽象业务问题、泛型问题、反射问题等。
潜入篇—Kotlin 探索(第 9~11 章),探索 Kotlin 在设计模式、函数式编程、异步和并发等编程领域的应用,其中包括对 4 大类设计模式、Typeclass 实现、函数式通用结构设计、类型替代异常处理、共享资源控制、CQRS 架构等重点内容的深入剖析;
遨游篇—Kotlin 实战(第 12~13 章),着重演示了 Kotlin 在 Android 和 Web 平台的实战案例,其中涉及架构方式、单向数据流模型、解耦视图导航、响应式编程、Spring 5 响应式框架和编程等内容。

之所以不能说 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,除了不代表任何意义的以外,它与其他常规类型并没有什么差别。

Kotlin核心编程(33):基础语法 2.4.2

购书地址 https://item.jd.com/12519581.html?dist=jd

评论

发布