先看一下拓展函数的语法结构,如下:
fun ClassName.methodName (param1:Int ,param2:Int) :Int {
return 0
}
相比于定义一个普通函数,定义拓展函数只需要在函数名的前面加上一个ClassName.
的语法结构,就表示将该函数添加到指定类当中了.
我们再回过头看一下什么是拓展函数?
拓展函数表示即使在不修改某个类的源码的情况下,仍然可以打开这个类,向该类添加新的函数.
为了更好理解拓展函数,我们以以下功能为例.
一个字符串中可能包含字母、数字和特殊符号等字符,现在我们希望统计字符串中字母的数量,你要怎么实现这个功能呢?如果按照一般的编程思维,可能大多数人会很自然地写出如下函数:
object StringUtil {
fun lettersCount(str: String): Int {
var count = 0
for (char in str) {
if (char.isLetter()) {
count++
}
}
return count
}
}
这里先定义了一个StringUtil单例类,然后在这个单例类中定义了一个lettersCount() 函数,该函数接收一个字符串参数.在lettersCount()方法中,我们使用for-in 循环去遍历字符串中的每一个字符.如果该字符串是一个字母的话,那么就将计数器加1,最终返回计数器的值.
val str = "ABC123xyz!@#"
val count = StringUtil.lettersCount(str)
System.out.println(count)
这种写法绝对可以正常工作,并且这也是Java编程中最标准的实现思维.但是有了拓展函数之后就不一样了,我们可以使用一种更加面向对象的思维来实现这个功能,比如说将lettersCount() 函数添加到String类当中.
由于我们希望向String类中添加一个拓展函数,因此需要先创建一个String.kt 文件. 文件名虽然并没有固定的要求,但是我建议向哪个类添加拓展函数,就定义一个同名的Kotlin文件,这样便于你以后查找.当然,拓展函数也是可以定义在任何一个现有类当中的,并不一定非要创建新文件. 不过通常来说,最好将它定义成顶层方法,这样可以让拓展函数拥有全局的访问域.
通过对比我们可以发现,我们将lettersCount( ) 方法定义成了String类的拓展函数,那么函数就自动拥有了String实例的上下文.因此lettersCount( ) 函数就不再需要接收一个字符串参数了, 而是直接遍历this即可,因为现在this就代表着字符串本身.
根据上面拓展函数的写法, 编写如下:
fun String.lettersCount(): Int {
var count = 0
for (char in this) {
if (char.isLetter()) {
count++
}
}
return count
}
定义好了拓展函数之后,统计某个字符串中的字母数量只需要这样写即可:
val count = "ABC123xyz!@#".lettersCount()
是不是很神奇? 看上去就好像是String类中自带了lettersCount() 方法一样.
拓展函数在很多情况下让API变得更加简洁、丰富,更加面向对象.我们再次以String类为例,这是一个final类,任何一个类都不可以继承它,也就是说它的API只有固定的那些而已,至少在Java中就是如此.然而到了Kotlin中就不一样了,我们可以向String类中拓展任何函数, 使它的API变得更加丰富.
当然,拓展函数的范围,不光是String类一种,你还可以向任何类中添加拓展函数. Kotlin对此基本没有限制.如果你能利用好拓展函数这个功能,将会大幅度地提升你的代码质量和开发效率.