【用 Kotlin 写 Android】Kotlin Koans 深入分析讲解(上)

前言

具体 Kotlin 是什么?我相信你已经在网络上其他地方看到过解释,这里不再赘述,简单一句话:“Kotlin 是一种与 Java、C++ 平级的函数式编程语言”。在上一篇文章中,我们应该看到了,Kotlin 有很多的基础特殊的语法,让代码变得简单清晰 (可能在开始的时候你反而觉得变得复杂了),但 Kotlin 真的就是语法的改变吗?花两个小时看看 Kotlin 的语法就算学完了 Kotlin 吗?非也!Kotlin 与 Java 最大的区别是 Kotlin 的函数式编程,这一点以后我们会经常提到,Kotlin 的核心与 Java 就有本质的不同。Kotlin Koans 是学习 Kotlin 极好的学习资料,我们先把 Kotlin Koans 做一遍,相信你会对 Kotlin 有完全不同的认识。

Kotlin Koans 项目详解

Kotlin Koans 是一个 Kotlin 学习的教程,采用的方式是给你未完成的代码,给你一点提示,你去补全代码,运行单元测试,通过后进入下一题,可以非常好的学习 Kotlin。

Kotlin Koans 的安装,可以在 GitHub 上下载源代码项目,但是我不建议这样做,我建议的方式是安装 EduTools 插件,安装方式是直接在插件中心中搜索 EduTools 就可以了:

图片

然后重启 Android Studio。可以看到第一项 Browse Courses:

图片

点击选择 Kotlin Koans 项目:

图片

大约需要一分钟后,会创建项目:

图片

感觉提示,完成第一个任务:

图片

这个任务就是上一篇中函数的定义相关的内容,我们可以看到得到如下一些信息:

  1. Kotlin 文件后缀为 .kt
  2. Kotlin 文件不需要定义类,可以直接定义方法
  3. 简单的方法可以省略大括号,直接在 = 后写返回值

每一个 Task 详解

Task 2:Java to Kotlin conversion

图片

将 Java 代码转换成 Kotlin 写法。我们打开 JavaCode.java 文件,选中 toJSON 方法,复制,到 Task.kt 中粘贴(粘贴需要选中代码),粘贴后可以发现 Java 代码自动转换成了 Kotlin 代码,很方便。

图片
图片

除了上面这种方法,还可以用 Android Studio 中代码装换工具,将 Java 文件转换成 Kotlin:

图片
图片

我们在这里注意几个问题:

  1. 函数的定义,用 fun 关键字
  2. 参数先写参数名,再写参数类型,中间用冒号 : 分割
  3. 方法参数后和大括号中间需要写函数返回值类型,用 : 说明
  4. 创建对象没有 new 关键字,直接类名后跟括号创建新对象
  5. 属性定义用 val(不可更改) 或 var(可以更改)

Task 3:Named arguments

图片

Kotlin 中参数是可以有默认值的,并且在调用的时候,可以显示声明哪些变量用哪些值,而不一定必须要按顺序赋值,其他的值使用默认值,很方便灵活,这样就可以减少构造函数、重载函数的数量。Java 中两个重载函数参数的类型如果都一样的话,是不允许的,但是 Kotlin 使用默认值的方式就可以很好的避免这个问题(声明一个三个参数的方法,并加上默认值,调用的时候对不同的参数进行声明赋值,就可以达到 Java 需要多个不同类型从在才能达到的目的)。

/**
 * Creates a string from all the elements separated using [separator] and using the given [prefix] and [postfix] if supplied.
 *
 * If the collection could be huge, you can specify a non-negative value of [limit], in which case only the first [limit]
 * elements will be appended, followed by the [truncated] string (which defaults to "...").
 */
public fun <T> Iterable<T>.joinToString(separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): String {
    return joinTo(StringBuilder(), separator, prefix, postfix, limit, truncated, transform).toString()
}
图片

Task 4:Default arguments

图片

看题目可以看出,有些方法在调用的时候报错,提示有些值没有别赋值,那我们的任务就是在函数定义的时候加上合适的默认值,分析提示给出的 Java 代码,我们可以看到,最后一个如果 number 没有被赋值,会用默认值 42 调用第二个方法,而第二个方法 toUpperCase 没有被赋值,使用默认值 false 调用第一个方法,则可以写出答案:

图片
图片

在这里我们可以看到合理的使用默认值,可以极大的简化代码。

Task 5:Lambdas

图片

找偶数很简单,每一个都分别除 2 看余数是否为 0,但是刚刚看到这道问题可能会摸不着头脑,怎么写,这什么意思呀?题目名称叫 Lambdas,Java 8 中支持 Lambda 表达式,Kotlin 也同样支持,怎么写呢。如果想解决这个问题,我们最好解决几个概念:

  • 函数在 Kotlin 中是一等公民(First-class function)
    • 函数可以像变量一样传递给其他函数作为参数(某一个函数有参数,这个参数是一个变量)
    • 函数可以作为其他函数的返回值
    • 函数可以用于给变量赋值可以存储在数据结构中
  • 高阶函数(Higher-Order Functions)
    • 函数作为函数的参数
    • 函数作为函数的返回值
  • 函数式编程(Functional programming)
    • 函数式编程是和面向对象、面向过程同一级别的编程方法或编程模式
    • 函数是一等公民是函数式编程的必要条件,经常用在高阶函数中
    • 后面我们会有单独的文章介绍函数式编程
图片

我们可以看到 any 函数的定义,predicate 参数是一个函数,这个函数的返回值是一个 Boolean 类型的值:

图片
图片
图片
图片

简化到最后,就很简单了。有没有觉得函数式编程特别神奇呢?

Task 6:Strings

图片

Kotlin 字符串可以像 Java 一样,也可以用三个双引号声明,三个双引号声明的字符串其中可以包含多行。字符串模板可以很方便在字符串中使用变量,则这个题的答案就是:

图片

这里我们用了 trimIndent() 方法对缩进进行格式化,还可以使用 trimMargin(),如下图,其中的竖线 | 是trimMaring 默认格式化特殊字符:

图片

Task 7:Data classes

图片

Date Class 是什么东西?我们先来了解 Kotlin 中集中数据结构:

  • Class
    • 与 Java 类类似,是一种数据结构
    • Kotlin 中的 Class 继承自 Any,而不是 Object
    • 用关键字 constructor 声明构造函数,够着函数可以有默认值
    • 构造函数分为主构造函数和二级构造函数,主构造函数跟在类名后由关键字 constructor 和参数表共同构成,二级构造函数在类中,用 constructor 和参数列表构成,注意如果有主构造函数,二级函数必须调用主构造函数。如 constructor(name: String, parent: Person) : this(name)
    • 主构造函数无法执行代码,如果需要执行一些代码时,可以用 init{} 在类中执行,可以声明多个 init{},执行顺序与声明顺序一致。
    • 默认类不可以被集成,方法不可以被重写,如果希望类被继承或方法可以被重写,可以在类或方法前加 open 关键字。
    • 子类在重写父类方法时,需要在方法前加 override 关键字
    • super 关键字调用父类方法
    • abstract 关键字定义抽象类,interface 关键字定义接口。
    • 普通情况下,类没有静态方法,如果需要静态发发或所有静态属性,需要用伴随对象 companion object,相当于独立于类开辟了一块空间,所有对象共有。
  • Properties and Fields
    • val 修改不可更改的属性
    • var 修饰可以更改的属性
    • lateinit 修饰延迟加载的属性,在需要用的时候才初始化。
  • Data Class
    • 有些时候,创建类就是为了让其可以有几个属性,Java 中的 Bean 对象,而在 Kotlin 中,将这种数据结构单独定义为 data class
    • 其中会自动创建一些方法,如 copy()equals()
    • 我们在后面会有主题讲解 data class
图片

data class 可以很简单的定义数据结构,并且其中自动包含了 get/set 方法,易读且方便。

Task 8:Nullable type

图片

Java 中经常需要判空,如果不为空,获取其中某些属性值等,写起来不优雅,且不安全,Kotlin 中采用了更简单的方式。

图片

注意,这并不意味着 Kotlin 中就完全不需要关心变量为空引起的错误,我们后面会具体详细说明一些 Java 代码转成 Kotlin 或直接 写 Kotlin 代码引起的一些错误,是一个需要填的坑。

Task 9:Smart casts

图片

自动类型转换是一个很聪明的特性。Kotlin 中没有 switch-case,代替它的是 when,这里的例子是判断 expr 具体是哪一种类型,这里可以展现出 Kotlin 强大的是在判断一个对象是哪一种类型后,后面这个变量直接转换成该类型,而不像 Java 中需要强转。

图片

Task 10:Extension functions

图片

扩展函数。有些时候,某些类功能不够强大,你希望扩展这个类,而你又不能修改该类的源代码,如果是 Java,你可能需要继承自功能不够强大的类,添加新方法,然后使用新的类,这比较麻烦,也可能会因为需求的变更,这个类越来越不好维护。Kotlin 的方式是在不修改原来的类的代码的情况下,扩展方法出新的方法,使用起来就像是在原来的类中添加了新的方法。

图片

在没有修改 Int 和 Pair 对象的情况下,他们都有了转成有理数的方法了。

Task 11:Object expressions

图片

对象表达式。Kotlin 的对象表达式与 Java 中的匿名内部类差不多。有些情况只用一次的对象,没必要写成一个类。

图片

简化代码改为 Lambda 表达式:

图片

再简化代码,使用 Kotlin stdlib:

图片

了解越多 Kotlin stdlib 中的方法,写代码越快,效率越高。

Task 12:Extension functions on collections

Kotlin 在集合类中做了大量的优化,提供了大量的有用的方法,这里排序可以直接调用。

/**
 * Returns a list of all elements sorted descending according to their natural sort order.
 */
public fun <T : Comparable<T>> Iterable<T>.sortedDescending(): List<T> {
    return sortedWith(reverseOrder())
}

Kotlin 提供了自然序的升序降序排序方法:sortedDescending

图片

Task 13:Comparison

图片

我们定义了一个类 MyDate,我们现在直接用 < 对这个类的对象比较大小。我们需要对这个对象定义比较大小操作符,则只需重写 compareTo 方法就可以了。

图片

Task 14:Task In range

图片

有了上面的经验,这里只需了解 in 操作符是调用的 contains 方法就可以了:

图片

简写成(其中 .. 就是执行 rangeTo 方法):

图片

Task 15:Range to

图片
图片
图片

我们在上一个任务中,有编译器自动提示使用了 in - .. 操作符,我们点进去看看,发现其实就是执行了 rangeTo 方法,这一个任务中,我们就需要实现 rangeTo 方法就可以,rangeTo 方法返回值是 ClosedRange,而 ClosedRange 需要对象实现比较大小 compareTo 方法,恰好我们上一节中已经在 MyData 中实现了 compareTo,恰好 DateRange 实现了 ClosedRange,因此我们可以直接使用,结果如下:

图片

这个任务比较复杂,但是逻辑是很清晰的。

Task 16:For loop

图片

For 循环需要迭代器,DateRange 需要实现 Iterable,则问题就简单了:

图片

当然,可以优化代码:

图片

For 循环就是迭代器的遍历。

Task 17:Operators overloading

图片

+ 操作符,其实就是实现 plus 方法。* 操作符就是实现 times 方法

图片

Task 18:Destructuring declarations

图片

可以将对象属性值赋值给其他对象,要求这个对象必须由 data 修饰。

图片

Task 19:Invoke

[图片上传失败...(image-63c82c-1523208961981)]

图片

小结

本文主要了解了一些 Kotlin 的具体实现方法,对真正写 Kotlin 程序极有好处。

到这里,我们完成了一半的任务,为避免篇幅过长,下面的任务我们在下一篇文章中继续讨论。


如果有一天你觉得过的舒服了,你就要小心了!欢迎关注我的公众号:我是任玉琢

qrcode_for_gh_45402a07f7d9_258
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容