学习Kotlin之编写好用的工具
1 求N个数的最大最小值
我们会想到用max()函数,但是它只能接受两个参数,如果需要比较的数量比较多,写起来就麻烦了。
这个时候我们就可以使用vararg关键字,它允许方法接收多个同类型的参数。
于是,新建一个Max.kt文件,自定义一个max()函数:
fun max(vararg nums: Int): Int { var maxNum = Int.MIN_VALUE for (num in nums) { maxNum = kotlin.math.max(maxNum,num) } return maxNum }
写法就如下所示:
val a = 10 val b = 20 val c = 30 val largest = max(a,b,c)
不过目前这个max()函数还有一个缺点,就是它只能求N个整型数字的最大值,如果想要求N个浮点型或者长整型数字的最大值,该怎么办呢?这里就有一种巧妙的做法。
Java中规定,所有类型的数字都是可比较的,因此必须实现Comparable接口,这个规定在Kotlin中也成立。
那么我们就可以借助泛型,将max()函数修改为可以接收任意多个实现Comparable接口的参数:
fun <T : Comparable<T>> max(vararg nums: T): T { if (nums.isEmpty()) throw RuntimeException("Params can not be empty.") var maxNum = nums[0] for (num in nums) { if (num > maxNum) maxNum = num } return maxNum }
这里将泛型T的上界指定成了Comparable<T>,那么参数T必定就是Comparable<T>的子类型了。接着同样遍历寻找最大值。
现在不管是双精度浮点型、单精度浮点型,还是其他类型的,只要是实现了Comparable接口的子类型,max()函数都支持获取最大值。
2 简化Toast的用法
Toast的标准写法如下:
Toast.makeText(context, "content", Toast.LENGTH_SHORT).show()
每次使用的时候都要写这么一长串的代码,确实麻烦。
我们可以在String类和Int类各添加一个扩展函数,并在里面封装Toast的使用方法。这样以后使用的时候就调用它们的扩展函数即可。
新建一个Toast.kt文件:
fun String.showToast(context: Context) { Toast.makeText(context, this, Toast.LENGTH_SHORT).show() } fun Int.showToast(context: Context) { Toast.makeText(context, this, Toast.LENGTH_SHORT).show() }
经过这样的扩展之后,使用方法就变简单了:
"This is a Toast.".showToast(context)
当然,你也可以弹出一个定义在strings.xml中的字符串资源:
R.string.app_name.showToast(context)
如果我们需要手动传入显示时长参数的话,可以使用参数默认值的功能,就可以在不增加showToast()函数的使用复杂度的情况下,还能动态支持设置显示时长的功能。如下:
fun String.showToast(context: Context, duration: Int = Toast.LENGTH_SHORT) { Toast.makeText(context, this, duration).show() } fun Int.showToast(context: Context, duration: Int = Toast.LENGTH_SHORT) { Toast.makeText(context, this, duration).show() }
这样就可以手动指定时长,不写就用默认值。
3 简化Snackbar的用法
Snackbar的常规用法:
Snackbar.make(view, "this is a Snackbar.", Snackbar.LENGTH_SHORT) .setAction("Action"){ // 处理具体逻辑 } .show()
由于make()方法接收一个View参数,Snackbar会使用这个View自动查找最外层布局展示Snackbar。因此我们可以给View类添加一个扩展函数,并在里面封装Snackbar的逻辑。新建一个Snackbar.kt文件:
fun View.showSnackbar(text: String, duration: Int = Snackbar.LENGTH_SHORT) { Snackbar.make(this, text, duration).show() } fun View.showSnackbar(resId: Int, duration: Int = Snackbar.LENGTH_SHORT) { Snackbar.make(this, resId, duration).show() }
这段代码跟上一节代码相似,只不过这里是将扩展函数添加到了View类中。这里也是支持传入字符串和字符串资源id的。
使用方式:
view.showSnackbar("this is a snackbar.")
但是这里缺少了setAction()方法,这时候就要用上高阶函数了,我们让showSnackbar()函数再接收一个函数类型参数:
fun View.showSnackbar(text: String, actionText: String? = null, duration: Int = Snackbar.LENGTH_SHORT, block: (() -> Unit)? = null) { val snackbar = Snackbar.make(this, text, duration) if (actionText != null && block != null){ snackbar.setAction(actionText){ block() } } snackbar.show() } fun View.showSnackbar(resId: Int, actionResId: Int? = null, duration: Int = Snackbar.LENGTH_SHORT, block: (() -> Unit)? = null) { val snackbar = Snackbar.make(this, resId, duration) if (actionResId != null && block != null){ snackbar.setAction(actionResId){ block() } } snackbar.show() }
这里添加了函数类型参数,还新增了一个用于传递给setAction()方法的字符串或字符串资源id。将这连个参数都设置成可为空类型,并将默认值设置成空,然后只有当这两个参数都不为空时,才调用setAction()方法设置额外的点击事件。如果触发了点击事件,只需要调用函数类型参数将事件传递给外部的Lambda表达式即可。
此时,showSnackbar()函数就比较完整了。写法如下:
view.showSnackbar("this is a snackbar.", "Action") {
// 处理逻辑
}
本次学习中,分别应用了顶层函数、扩展函数和高阶函数的知识,还有vararg、参数默认值等技巧。

浙公网安备 33010602011771号